committed by
crueter
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
95 changed files with 5292 additions and 1 deletions
-
2src/CMakeLists.txt
-
82src/eden/.gitignore
-
82src/eden/CMakeLists.txt
-
9src/eden/gamepad/CMakeLists.txt
-
78src/eden/gamepad/gamepad.cpp
-
31src/eden/gamepad/gamepad.h
-
14src/eden/icons.qrc
-
1src/eden/icons/audio.svg
-
39src/eden/icons/back.svg
-
1src/eden/icons/controls.svg
-
1src/eden/icons/cpu.svg
-
1src/eden/icons/debug.svg
-
39src/eden/icons/forward.svg
-
1src/eden/icons/general.svg
-
60src/eden/icons/graphics.svg
-
1src/eden/icons/help.svg
-
1src/eden/icons/system.svg
-
13src/eden/interface/CMakeLists.txt
-
22src/eden/interface/MetaObjectHelper.h
-
261src/eden/interface/QMLSetting.cpp
-
105src/eden/interface/QMLSetting.h
-
124src/eden/interface/SettingsInterface.cpp
-
84src/eden/interface/SettingsInterface.h
-
562src/eden/interface/qt_config.cpp
-
55src/eden/interface/qt_config.h
-
569src/eden/interface/shared_translation.cpp
-
65src/eden/interface/shared_translation.h
-
112src/eden/interface/uisettings.cpp
-
282src/eden/interface/uisettings.h
-
56src/eden/main.cpp
-
16src/eden/models/CMakeLists.txt
-
70src/eden/models/GameListModel.cpp
-
39src/eden/models/GameListModel.h
-
90src/eden/models/SettingsModel.cpp
-
42src/eden/models/SettingsModel.h
-
5src/eden/qml/CMakeLists.txt
-
57src/eden/qml/config/CMakeLists.txt
-
73src/eden/qml/config/GlobalConfigureDialog.qml
-
8src/eden/qml/config/SectionHeader.qml
-
92src/eden/qml/config/Setting.qml
-
39src/eden/qml/config/TestSetting.qml
-
160src/eden/qml/config/fields/BaseField.qml
-
27src/eden/qml/config/fields/ConfigCheckbox.qml
-
33src/eden/qml/config/fields/ConfigComboBox.qml
-
26src/eden/qml/config/fields/ConfigHexEdit.qml
-
28src/eden/qml/config/fields/ConfigIntLine.qml
-
39src/eden/qml/config/fields/ConfigIntSlider.qml
-
25src/eden/qml/config/fields/ConfigIntSpin.qml
-
22src/eden/qml/config/fields/ConfigStringEdit.qml
-
27src/eden/qml/config/fields/ConfigTimeEdit.qml
-
17src/eden/qml/config/fields/FieldCheckbox.qml
-
18src/eden/qml/config/fields/FieldLabel.qml
-
1src/eden/qml/config/icons.qrc
-
47src/eden/qml/config/pages/SettingsList.qml
-
17src/eden/qml/config/pages/audio/AudioGeneralPage.qml
-
17src/eden/qml/config/pages/cpu/CpuGeneralPage.qml
-
19src/eden/qml/config/pages/debug/DebugAdvancedPage.qml
-
18src/eden/qml/config/pages/debug/DebugCpuPage.qml
-
28src/eden/qml/config/pages/debug/DebugGeneralPage.qml
-
20src/eden/qml/config/pages/debug/DebugGraphicsPage.qml
-
18src/eden/qml/config/pages/general/UiGameListPage.qml
-
23src/eden/qml/config/pages/general/UiGeneralPage.qml
-
14src/eden/qml/config/pages/global/GlobalAudioPage.qml
-
14src/eden/qml/config/pages/global/GlobalCpuPage.qml
-
17src/eden/qml/config/pages/global/GlobalDebugPage.qml
-
17src/eden/qml/config/pages/global/GlobalGeneralPage.qml
-
16src/eden/qml/config/pages/global/GlobalGraphicsPage.qml
-
18src/eden/qml/config/pages/global/GlobalSystemPage.qml
-
34src/eden/qml/config/pages/global/GlobalTab.qml
-
16src/eden/qml/config/pages/global/GlobalTabSwipeView.qml
-
17src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml
-
17src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml
-
17src/eden/qml/config/pages/graphics/RendererPage.qml
-
17src/eden/qml/config/pages/system/AppletsPage.qml
-
17src/eden/qml/config/pages/system/FileSystemPage.qml
-
17src/eden/qml/config/pages/system/SystemCorePage.qml
-
22src/eden/qml/config/pages/system/SystemGeneralPage.qml
-
23src/eden/qml/constants/CMakeLists.txt
-
24src/eden/qml/constants/Constants.qml
-
79src/eden/qml/items/AnimatedDialog.qml
-
59src/eden/qml/items/BetterMenu.qml
-
33src/eden/qml/items/BetterMenuBar.qml
-
22src/eden/qml/items/CMakeLists.txt
-
23src/eden/qml/items/IconButton.qml
-
40src/eden/qml/items/SettingsTabButton.qml
-
36src/eden/qml/items/StatusBarButton.qml
-
46src/eden/qml/items/VerticalTabBar.qml
-
68src/eden/qml/items/fields/BetterSpinBox.qml
-
38src/eden/qml/items/fields/BetterTextField.qml
-
20src/eden/qml/items/fields/FieldFooter.qml
-
13src/eden/qml/main/CMakeLists.txt
-
141src/eden/qml/main/GameList.qml
-
77src/eden/qml/main/GamePreview.qml
-
207src/eden/qml/main/Main.qml
-
160src/eden/qml/main/StatusBar.qml
@ -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*/ |
||||
@ -0,0 +1,82 @@ |
|||||
|
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 |
||||
|
) |
||||
|
|
||||
|
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} |
||||
|
) |
||||
@ -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 |
||||
|
) |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
}; |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -0,0 +1,13 @@ |
|||||
|
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 |
||||
|
|
||||
|
) |
||||
@ -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 |
||||
@ -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(); |
||||
|
} |
||||
@ -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 |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
#ifndef SETTINGSINTERFACE_H |
||||
|
#define SETTINGSINTERFACE_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
#include <QtQmlIntegration/QtQmlIntegration> |
||||
|
|
||||
|
#include "QMLSetting.h" |
||||
|
#include "shared_translation.h" |
||||
|
#include "yuzu/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 |
||||
@ -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.contains(category)) { |
||||
|
return Settings::values.linkage.by_category[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(); |
||||
|
} |
||||
@ -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; |
||||
|
}; |
||||
@ -0,0 +1,569 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include "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 "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()); |
||||
|
|
||||
|
// 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, tr("Use Fast GPU Time (Hack)"), |
||||
|
tr("Enables Fast GPU Time. This option will force most games to run at their highest " |
||||
|
"native resolution.")); |
||||
|
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.")); |
||||
|
|
||||
|
// Linux
|
||||
|
INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); |
||||
|
|
||||
|
// Ui Debugging
|
||||
|
|
||||
|
// Ui Multiplayer
|
||||
|
|
||||
|
// Ui Games list
|
||||
|
INSERT(UISettings, |
||||
|
grid_columns, |
||||
|
tr("Grid View Columns"), |
||||
|
tr("Number of games to show per row in the grid view.")); |
||||
|
|
||||
|
#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_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::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")), |
||||
|
}}); |
||||
|
|
||||
|
#undef PAIR
|
||||
|
#undef CTX_PAIR
|
||||
|
|
||||
|
return translations; |
||||
|
} |
||||
|
} // namespace ConfigurationShared
|
||||
@ -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 |
||||
@ -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
|
||||
@ -0,0 +1,282 @@ |
|||||
|
// 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, |
||||
|
}; |
||||
|
|
||||
|
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); |
||||
@ -0,0 +1,56 @@ |
|||||
|
#include "core/core.h"
|
||||
|
#include "interface/SettingsInterface.h"
|
||||
|
#include "interface/qt_config.h"
|
||||
|
#include "models/GameListModel.h"
|
||||
|
#include <QApplication>
|
||||
|
#include <QQmlApplicationEngine>
|
||||
|
#include <QQmlContext>
|
||||
|
|
||||
|
#include <QQuickStyle>
|
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
QApplication app(argc, argv); |
||||
|
|
||||
|
QQuickStyle::setStyle(QObject::tr("Material")); |
||||
|
|
||||
|
QCoreApplication::setOrganizationName(QStringLiteral("yuzu")); |
||||
|
QCoreApplication::setApplicationName(QStringLiteral("eden")); |
||||
|
|
||||
|
/// Settings, etc
|
||||
|
Settings::SetConfiguringGlobal(true); |
||||
|
QtConfig *config = new QtConfig; |
||||
|
config->SaveAllValues(); |
||||
|
|
||||
|
// TODO: Save all values on launch and per game etc
|
||||
|
app.connect(&app, &QCoreApplication::aboutToQuit, &app, [config]() { |
||||
|
config->SaveAllValues(); |
||||
|
}); |
||||
|
|
||||
|
/// Expose Enums
|
||||
|
|
||||
|
// Core
|
||||
|
std::unique_ptr<Core::System> system = std::make_unique<Core::System>(); |
||||
|
|
||||
|
/// CONTEXT
|
||||
|
QQmlApplicationEngine engine; |
||||
|
|
||||
|
// Enums
|
||||
|
qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "org.eden_emu.interface", 1, 0, "SettingsCategories", QString()); |
||||
|
|
||||
|
// Directory List
|
||||
|
GameListModel *gameListModel = new GameListModel(&app); |
||||
|
engine.rootContext()->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(); |
||||
|
} |
||||
@ -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 |
||||
|
) |
||||
@ -0,0 +1,70 @@ |
|||||
|
#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); |
||||
|
|
||||
|
qDebug() << path << name << size; |
||||
|
// m_data << Game{path, name, size};
|
||||
|
|
||||
|
QStandardItem *game = new QStandardItem(name); |
||||
|
game->setData(path, GLMRoleTypes::PATH); |
||||
|
game->setData(sizeString, GLMRoleTypes::FILESIZE); |
||||
|
|
||||
|
invisibleRootItem()->appendRow(game); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
@ -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; |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
#ifndef SETTINGSMODEL_H |
||||
|
#define SETTINGSMODEL_H |
||||
|
|
||||
|
#include <QAbstractListModel> |
||||
|
#include "yuzu/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 |
||||
@ -0,0 +1,5 @@ |
|||||
|
add_subdirectory(config) |
||||
|
add_subdirectory(constants) |
||||
|
add_subdirectory(items) |
||||
|
|
||||
|
add_subdirectory(main) |
||||
@ -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 |
||||
|
) |
||||
@ -0,0 +1,73 @@ |
|||||
|
import QtQuick |
||||
|
import QtQuick.Controls.Material |
||||
|
import QtQuick.Layouts |
||||
|
|
||||
|
import org.eden_emu.constants |
||||
|
import org.eden_emu.items |
||||
|
import org.eden_emu.interface |
||||
|
|
||||
|
Dialog { |
||||
|
preferredWidth: 1280 |
||||
|
|
||||
|
title: "Configuration" |
||||
|
standardButtons: Dialog.Ok | Dialog.Cancel |
||||
|
|
||||
|
onOpened: { |
||||
|
for (var tab in tabBar.children) { |
||||
|
console.log(tab) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onAccepted: { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
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 {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.constants |
||||
|
|
||||
|
Text { |
||||
|
color: Constants.text |
||||
|
font.pixelSize: 16 |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,160 @@ |
|||||
|
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 alias enable: enable.checked |
||||
|
property Item contentItem |
||||
|
|
||||
|
clip: true |
||||
|
height: content.height + (helpText.height + helpText.anchors.topMargin) |
||||
|
|
||||
|
function apply() { |
||||
|
setting.value = value |
||||
|
} |
||||
|
|
||||
|
function sync() { |
||||
|
value = setting.value |
||||
|
} |
||||
|
|
||||
|
RowLayout { |
||||
|
id: content |
||||
|
height: 45 * 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() |
||||
|
visible: setting.tooltip !== "" |
||||
|
z: 2 |
||||
|
} |
||||
|
|
||||
|
FieldCheckbox { |
||||
|
id: enable |
||||
|
setting: field.setting |
||||
|
z: 2 |
||||
|
} |
||||
|
|
||||
|
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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
import QtQuick |
||||
|
import QtQuick.Controls.Material |
||||
|
import QtQuick.Layouts |
||||
|
|
||||
|
import org.eden_emu.constants |
||||
|
|
||||
|
BaseField { |
||||
|
showLabel: false |
||||
|
// 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: setting.value = checked |
||||
|
|
||||
|
checkable: true |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(setting.value).toString(16) |
||||
|
suffix: setting.suffix |
||||
|
|
||||
|
onTextEdited: setting.value = Number("0x" + text) |
||||
|
} |
||||
|
} |
||||
@ -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: setting.value |
||||
|
suffix: setting.suffix |
||||
|
|
||||
|
onTextEdited: setting.value = parseInt(text) |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
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 { |
||||
|
contentItem: RowLayout { |
||||
|
Layout.fillWidth: true |
||||
|
|
||||
|
Slider { |
||||
|
Layout.fillWidth: true |
||||
|
|
||||
|
from: setting.min |
||||
|
to: setting.max |
||||
|
stepSize: 1 |
||||
|
|
||||
|
value: setting.value |
||||
|
|
||||
|
onMoved: setting.value = value |
||||
|
|
||||
|
Layout.rightMargin: 10 * Constants.scalar |
||||
|
|
||||
|
snapMode: Slider.SnapAlways |
||||
|
} |
||||
|
|
||||
|
Text { |
||||
|
font.pixelSize: 14 * Constants.scalar |
||||
|
color: Constants.text |
||||
|
|
||||
|
text: setting.value + setting.suffix |
||||
|
|
||||
|
Layout.rightMargin: 10 * Constants.scalar |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
import QtQuick |
||||
|
import QtQuick.Layouts |
||||
|
|
||||
|
import org.eden_emu.items |
||||
|
import org.eden_emu.config |
||||
|
import org.eden_emu.constants |
||||
|
|
||||
|
BaseField { |
||||
|
contentItem: BetterSpinBox { |
||||
|
enabled: enable |
||||
|
|
||||
|
Layout.fillWidth: true |
||||
|
Layout.rightMargin: 10 * Constants.scalar |
||||
|
|
||||
|
from: setting.min |
||||
|
to: setting.max |
||||
|
|
||||
|
font.pixelSize: 15 * Constants.scalar |
||||
|
|
||||
|
value: setting.value |
||||
|
label: setting.suffix |
||||
|
|
||||
|
onValueModified: setting.value = value |
||||
|
} |
||||
|
} |
||||
@ -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: setting.value |
||||
|
suffix: setting.suffix |
||||
|
|
||||
|
onTextEdited: setting.value = text |
||||
|
} |
||||
|
} |
||||
@ -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: setting.value |
||||
|
suffix: setting.suffix |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
import QtQuick |
||||
|
import QtQuick.Controls |
||||
|
import QtQuick.Layouts |
||||
|
|
||||
|
import org.eden_emu.constants |
||||
|
|
||||
|
CheckBox { |
||||
|
property var setting |
||||
|
|
||||
|
indicator.implicitHeight: 25 * Constants.scalar |
||||
|
indicator.implicitWidth: 25 * Constants.scalar |
||||
|
|
||||
|
checked: setting.other !== null ? setting.other.value : true |
||||
|
onClicked: setting.other.value = checked |
||||
|
|
||||
|
visible: setting.other !== null |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
<RCC/> |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["Audio"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
AudioGeneralPage {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["CPU"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
CpuGeneralPage {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["General", "Graphics", "Advanced", "CPU"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
DebugGeneralPage {} |
||||
|
DebugGraphicsPage {} |
||||
|
DebugAdvancedPage {} |
||||
|
DebugCpuPage {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["General", "Hotkeys", "Game List"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
// TODO: platform-specific stuff |
||||
|
UiGeneralPage {} |
||||
|
Item {} |
||||
|
UiGameListPage {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["Graphics", "Advanced", "Extensions"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
RendererPage {} |
||||
|
RendererAdvancedPage {} |
||||
|
RendererExtensionsPage {} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
import QtQuick |
||||
|
|
||||
|
import org.eden_emu.config |
||||
|
|
||||
|
GlobalTab { |
||||
|
tabs: ["System", "Core", "Profiles", "Filesystem", "Applets"] |
||||
|
|
||||
|
GlobalTabSwipeView { |
||||
|
id: swipe |
||||
|
currentIndex: tabBar.currentIndex |
||||
|
|
||||
|
SystemGeneralPage {} |
||||
|
SystemCorePage {} |
||||
|
Item {} |
||||
|
FileSystemPage {} |
||||
|
AppletsPage {} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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"] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
) |
||||
@ -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 |
||||
|
} |
||||
@ -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 {} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
) |
||||
@ -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 {} |
||||
|
} |
||||
@ -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 |
||||
|
// } |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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" |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
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 |
||||
|
GamePreview.qml |
||||
|
) |
||||
@ -0,0 +1,141 @@ |
|||||
|
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: make this optional. |
||||
|
// Probably just make a Gamepad frontend/backend split with a null backend |
||||
|
Gamepad { |
||||
|
id: gamepad |
||||
|
|
||||
|
onUpPressed: grid.moveCurrentIndexUp() |
||||
|
onDownPressed: grid.moveCurrentIndexDown() |
||||
|
onLeftPressed: grid.moveCurrentIndexLeft() |
||||
|
onRightPressed: grid.moveCurrentIndexRight() |
||||
|
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 |
||||
|
grid.anchors.bottom = root.bottom |
||||
|
EdenGameList.addDir(folder) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
GridView { |
||||
|
id: grid |
||||
|
|
||||
|
property int cellSize: Math.floor(width / setting.value) |
||||
|
|
||||
|
highlightFollowsCurrentItem: true |
||||
|
clip: true |
||||
|
|
||||
|
cellWidth: cellSize |
||||
|
cellHeight: cellSize + 60 * Constants.scalar |
||||
|
|
||||
|
anchors { |
||||
|
top: parent.top |
||||
|
left: parent.left |
||||
|
right: parent.right |
||||
|
|
||||
|
bottom: button.top |
||||
|
|
||||
|
margins: 8 |
||||
|
} |
||||
|
|
||||
|
model: EdenGameList |
||||
|
|
||||
|
delegate: GamePreview { |
||||
|
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" |
||||
|
} |
||||
|
|
||||
|
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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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" |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue