Compare commits
366 Commits
Author | SHA1 | Date | |
---|---|---|---|
a73a5d7e85 | |||
832a5e8852 | |||
96d1f0da2d | |||
597388ecda | |||
1cf6d7b7bb | |||
7bc9d0cdad | |||
dc0dbc50ab | |||
994f4dc77d | |||
c9e297b74c | |||
dd514a115c | |||
7e0b4bd538 | |||
378080eb87 | |||
e8f5e97fa4 | |||
f3873620a3 | |||
986ac9ff83 | |||
42b9c1e8fe | |||
3b375525fb | |||
e6658c133c | |||
5b42a4d2c4 | |||
8f0c89ffd6 | |||
2c9715acf6 | |||
274af65f69 | |||
4ca78eded5 | |||
6cb6b15612 | |||
2725e40838 | |||
c2e4c8f98e | |||
b53e7ffd46 | |||
ac66643346 | |||
21e88f17f6 | |||
5626f2ca1c | |||
402f05b8ef | |||
fb27042e01 | |||
69a9de33d3 | |||
bba51c2eeb | |||
fc26189fe1 | |||
a40c90e7dd | |||
f864a49014 | |||
ecbf303266 | |||
b3bf05356b | |||
cb4b58052f | |||
f8cdd5f484 | |||
22202be394 | |||
17ba217940 | |||
aae4595bdb | |||
880fd3cfcb | |||
f679f25e08 | |||
c2709b3bdd | |||
2b6e81deea | |||
7271f1b18e | |||
5fda543f84 | |||
95c06de4c1 | |||
49c63ea077 | |||
531da8a1c0 | |||
5cbdfbc7a4 | |||
e0544dd9c7 | |||
aa784c3e5e | |||
9205077590 | |||
0ed40c7175 | |||
40d47b7aa2 | |||
ec0bb74968 | |||
42f7f98666 | |||
95bad6995c | |||
3d42995822 | |||
9095941fd1 | |||
ba71141bdc | |||
0a0675a7f6 | |||
a7c6e6a8cf | |||
0bc8151c7e | |||
40c17673f5 | |||
a8950d6ac4 | |||
162798b026 | |||
1b28ecd63e | |||
895d9b53bc | |||
0e06aace45 | |||
adf4ebcd60 | |||
470a8031a4 | |||
5440d4ad5c | |||
dde208b480 | |||
4c3d2d5d75 | |||
fab11ba3f1 | |||
332891b5ff | |||
7df4fcada7 | |||
d6698680be | |||
e5c9838b0b | |||
f8ec878796 | |||
9ff21f9ab6 | |||
aa021085cf | |||
1f5d881860 | |||
1f664100bd | |||
1f5e1ffa80 | |||
264438ff19 | |||
3b8ac1641a | |||
4250732353 | |||
4d1579acbf | |||
6279f5e430 | |||
b7d2bff6aa | |||
7c327fecb3 | |||
cc1a933a2f | |||
dd574146fb | |||
2c94ac455e | |||
e18d258fa0 | |||
36f10df775 | |||
680e548022 | |||
21c4176157 | |||
3b4ff2d6d9 | |||
12504f280c | |||
250fc51374 | |||
206e0882c2 | |||
609abc8b9b | |||
cee7121058 | |||
cd124bda58 | |||
9f12e50a54 | |||
097562bc6c | |||
db4242c5dc | |||
4dd77316f7 | |||
3f98369a17 | |||
c26aeefe03 | |||
666e05f5cb | |||
8d9d508dc7 | |||
e27f5522e2 | |||
add2a9d151 | |||
9e50dd99d7 | |||
0dec91bb42 | |||
d9b63353b0 | |||
eabd0ec93f | |||
138d5dc64a | |||
3e68a87d63 | |||
69b6ef7a4a | |||
40e87c634e | |||
79d1c190db | |||
2bc88467eb | |||
baf8752e74 | |||
d5e4378aea | |||
6dbcdfea47 | |||
c5258cf082 | |||
5c89e22bb9 | |||
11ecff2ff0 | |||
4c3f09644a | |||
e187a8870a | |||
a64fee29dc | |||
9ef94c8292 | |||
915d6d044c | |||
a4780ab33b | |||
a947a45d81 | |||
9db73f74cf | |||
a1efd87c45 | |||
49be977588 | |||
c95be55091 | |||
63dedbda86 | |||
c532118d94 | |||
52d6f2e656 | |||
c9bc4eaf58 | |||
3249f8ff41 | |||
1b41b285ac | |||
f5a6f45b27 | |||
210557951b | |||
4c2d9ff3ff | |||
8198b99935 | |||
460f96967d | |||
7ca779a26d | |||
b5032b3c91 | |||
f0a3dff136 | |||
f659dcb9d8 | |||
a34fb0e939 | |||
21ce8a9b80 | |||
9ecbee8032 | |||
80519af67d | |||
26e30faff3 | |||
0992310b76 | |||
009c1101d2 | |||
ba95ee54ab | |||
4ce4299ca2 | |||
17620d18db | |||
9f1cf6458c | |||
67b4e63cff | |||
c05c688ee8 | |||
b2623dc27d | |||
5131b71437 | |||
7870423671 | |||
b72916fbc1 | |||
da073fce61 | |||
1fc90e57d2 | |||
eafcc314a9 | |||
6e9bd4de13 | |||
05a41b31bc | |||
eed17f963e | |||
c09c0c002d | |||
d56d335c0b | |||
23c844b2aa | |||
81691b9e37 | |||
2dc422bc14 | |||
a80fa5e33f | |||
954e995321 | |||
dad9ab6bb6 | |||
f0562b9c75 | |||
b8556530f2 | |||
4f3af839be | |||
155736c986 | |||
dba908dc78 | |||
ecee34a50c | |||
9b5a0c3889 | |||
80b4972139 | |||
5d85468302 | |||
9b1cc2cec6 | |||
e691622f0a | |||
f663a5cd38 | |||
f7c2e867f4 | |||
cedd200745 | |||
58207685c0 | |||
095ad923ad | |||
f07ae7d53f | |||
c308f09722 | |||
f1eef29409 | |||
1f8d66db7c | |||
c3a5716a95 | |||
1f1e2a7f03 | |||
e54f9dc4b4 | |||
edfd4d70c0 | |||
fc43aecbbd | |||
58d7a1fe97 | |||
7aa430f1a5 | |||
6bf460e104 | |||
efb135b74c | |||
a707842e14 | |||
a5a9b9bc8b | |||
17078ad929 | |||
32450d45de | |||
ed7a0474c6 | |||
fe9c49949a | |||
052b23c83c | |||
e4f68592c3 | |||
1dcd44b94f | |||
61b1ce252f | |||
5f38086f94 | |||
7bae440d3a | |||
f1943fd0b6 | |||
ec8d4f3af5 | |||
b3f0978869 | |||
f614d2c435 | |||
40c9416097 | |||
618c8edc79 | |||
99fc4fa61b | |||
f6d5499a16 | |||
26bf13a65d | |||
96cf242bcf | |||
59755818ef | |||
f8beeeb7d3 | |||
cb250162cb | |||
7528f94536 | |||
43081c16c4 | |||
780627e7b0 | |||
9044cb38d1 | |||
a53cfdab78 | |||
c7f9962dde | |||
296c4a3d01 | |||
e7cf4e6eaf | |||
a1a4771ac1 | |||
2fd819613f | |||
ad6ff6ce99 | |||
dc30d94852 | |||
4f293f8cbe | |||
32a1cd83fd | |||
e3d0ccf8d5 | |||
c14844d12c | |||
7fea26e97e | |||
7b7f62c776 | |||
423dbc8888 | |||
6adf15e479 | |||
2747f12591 | |||
a47824f961 | |||
8474d52778 | |||
dd7a924596 | |||
a76eaf9a9a | |||
009e6bcd1b | |||
eb2cc159fa | |||
bb89e36fd8 | |||
de3134adbe | |||
36d53819a4 | |||
ae4324032a | |||
f449895e6d | |||
410be95ab6 | |||
cff9046fc7 | |||
86fd0643c2 | |||
43a83a401e | |||
f0e27a23a5 | |||
e68650237d | |||
1faff14e73 | |||
784cf9d594 | |||
64263c5218 | |||
065c4e520d | |||
139a930407 | |||
719dc97bbd | |||
41bba5310a | |||
8071c8c8c0 | |||
b402b4e7f6 | |||
93df366b2c | |||
cd3a15aea5 | |||
070136b3f7 | |||
08ab47c6c0 | |||
85faa9d8fa | |||
dca5b14493 | |||
4d2c8e2a44 | |||
8fa248ceb4 | |||
30862b5ffd | |||
9f57747c57 | |||
fe29a2ff6e | |||
e9a173e00c | |||
a11784fcbf | |||
fd36c8deca | |||
70638340b3 | |||
4b495f3333 | |||
934b5a64e5 | |||
cee667b491 | |||
94a64f2aea | |||
2355c2af62 | |||
5e0f8e8738 | |||
d16288a2a8 | |||
600f86dc7b | |||
7210c17c5e | |||
a16854e55a | |||
3e455a90a1 | |||
e4413542b2 | |||
8c720783f5 | |||
8734ea9dd4 | |||
c586e6d2b7 | |||
3a4eeb77fe | |||
51b3953cfc | |||
610eecc1c1 | |||
492056abf6 | |||
ee6e682ab4 | |||
6f60e102a2 | |||
eeb2af9953 | |||
550747eac6 | |||
3ffceab1fb | |||
b9f2a96595 | |||
cbaa845f5d | |||
9e2681f2d7 | |||
81fae0d1a6 | |||
38519f3b9a | |||
7f27aabbd0 | |||
e876c43ce9 | |||
8639245533 | |||
d6b86a6629 | |||
8f2b7b5b8e | |||
fc4b7cba2c | |||
08831eecf7 | |||
c6a139a6e7 | |||
02714a1291 | |||
09c9686498 | |||
b6614c6ad5 | |||
b1d4b174a6 | |||
2b23463daa | |||
9dfe81770a | |||
52c115a1f8 | |||
e20abbf9cc | |||
76671d63d4 | |||
3d1a0bf374 | |||
c20f3fbebd | |||
0d3b82477e | |||
470be03c2f | |||
c963b3c804 | |||
a4fdfb5f94 | |||
37d27c4c99 | |||
f906eb06c2 | |||
219f63ff4e | |||
1cca3e99ab |
@ -63,6 +63,10 @@ dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# Namespace preferences
|
||||
csharp_style_namespace_declarations = block_scoped:warning
|
||||
resharper_csharp_namespace_body = block_scoped
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
|
61
.gitattributes
vendored
61
.gitattributes
vendored
@ -1,63 +1,4 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
* text=auto eol=lf
|
||||
|
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,43 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ Lines between [ ] (square brackets) should be removed before posting. ]
|
||||
|
||||
### What's the issue you encountered?
|
||||
|
||||
[ Describe the issue in detail and what you were doing beforehand. ]</br>
|
||||
[ Did you make any changes related to Ryujinx itself? ]</br>
|
||||
[ If so, make sure to include details relating to what exactly you changed. ]
|
||||
|
||||
### How can the issue be reproduced?
|
||||
|
||||
[ Include a detailed step by step process for recreating your issue. ]
|
||||
|
||||
### Log file
|
||||
|
||||
[ Logs files can be found under ``Logs`` folder in Ryujinx program folder. ]</br>
|
||||
[ If you don't include a crash report in instances of crash related issues, we will ask you one to provide one. ]
|
||||
|
||||
### Environment?
|
||||
|
||||
- Ryujinx version: 1.0.X</br>
|
||||
[ Replace X's with the Ryujinx version at time of crash. ]
|
||||
- Game version: X.X.X</br>
|
||||
[ Replace X's with the game version at time of crash. ]
|
||||
- System Specs:
|
||||
- OS: *(e.g. Windows 10)*
|
||||
- CPU: *(e.g. i7-6700)*
|
||||
- GPU: *(e.g. NVIDIA RTX 2070)*
|
||||
- RAM: *(e.g. 16GiB)*
|
||||
- Applied Mods : [ Yes (Which ones) / No ]
|
||||
|
||||
### Additional context?
|
||||
|
||||
Additional info about your environment:</br>
|
||||
[ Any other information relevant to your issue. ]
|
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Description of the issue
|
||||
description: What's the issue you encountered?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: How can the issue be reproduced?
|
||||
placeholder: Describe each step as precisely as possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: "e.g. Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ryujinx-version
|
||||
attributes:
|
||||
label: Ryujinx version
|
||||
placeholder: "e.g. 1.0.470"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: game-version
|
||||
attributes:
|
||||
label: Game version
|
||||
placeholder: "e.g. 1.1.1"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "e.g. i7-6700"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "e.g. NVIDIA RTX 2070"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: RAM
|
||||
placeholder: "e.g. 16GB"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: mods
|
||||
attributes:
|
||||
label: List of applied mods
|
||||
placeholder: You can list applied mods here.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context?
|
||||
description: |
|
||||
- Additional info about your environment:
|
||||
- Any other information relevant to your issue.
|
||||
validations:
|
||||
required: false
|
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest a new feature for Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Feature Request
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]</br>
|
||||
|
||||
[ Please search for existing [feature requests](https://github.com/Ryujinx/Ryujinx/issues) before you make your own request. ]</br>
|
||||
[ Duplicate requests will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What feature are you suggesting?
|
||||
#### Overview:
|
||||
- [ Include the basic, high-level concepts for this feature here. ]
|
||||
|
||||
#### Smaller Details:
|
||||
- [ These may include specific methods of implementation etc. ]
|
||||
|
||||
#### Nature of Request:
|
||||
[ Remove all that do not apply to your request. ]
|
||||
- Addition
|
||||
- [ Ex: Addition of certain original features or features from other community projects. ]
|
||||
- [ If you are suggesting porting features or including features from other projects, include what license they are distributed under and what, if any libraries those project use. ]
|
||||
- Change
|
||||
- Removal
|
||||
- [Ex: Removal of certain features or implementation due to a specific issue/bug or because of low quality code, etc.]
|
||||
|
||||
### Why would this feature be useful?
|
||||
[ If this is a feature for an end-user, how does it benefit the end-user? ]</br>
|
||||
[ If this feature is for developers, what does it add to Ryujinx that did not already exist? ]
|
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
body:
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
label: Overview
|
||||
description: Include the basic, high-level concepts for this feature here.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: details
|
||||
attributes:
|
||||
label: Smaller details
|
||||
description: These may include specific methods of implementation etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Nature of request
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
validations:
|
||||
required: true
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Missing CPU Instruction
|
||||
about: CPU Instruction is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing CPU Instruction
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing CPU instruction](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1405) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What CPU instruction is missing?
|
||||
|
||||
Requires the *INSTRUCTION* instruction.</br>
|
||||
[ Replace *INSTRUCTION* by the instruction name, e.g. VADDL.U16 ]
|
||||
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Add the undefined instruction error message in the above code block ]
|
||||
|
||||
### Instruction name
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this instruction ]
|
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Missing CPU Instruction
|
||||
description: CPU Instruction is missing in Ryujinx.
|
||||
title: "[CPU]"
|
||||
labels: [cpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: CPU instruction
|
||||
description: What CPU instruction is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Instruction name
|
||||
description: Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
|
||||
validations:
|
||||
required: true
|
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
@ -1,35 +0,0 @@
|
||||
---
|
||||
name: Missing Service Call
|
||||
about: Service call is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing Service Call
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing service call](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1431) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What service call is missing?
|
||||
|
||||
*SERVICE* *INTERFACE*: *NUMBER* (*NAME*) is not implemented.</br>
|
||||
[ Replace *SERVICE* by the service name, e.g. appletAE ]</br>
|
||||
[ Replace *INTERFACE* by the interface name, e.g. IAllSystemAppletProxiesService ]</br>
|
||||
[ Replace *NUMBER* by the call number, e.g. 100 ]</br>
|
||||
[ Replace *NAME* by the call name, e.g. OpenSystemAppletProxy ]</br>
|
||||
[ e.g. appletAE IAllSystemAppletProxiesService: 100 (OpenSystemAppletProxy) ]
|
||||
|
||||
[ Add related links to the specific call from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) ]
|
||||
|
||||
### Service description
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this call ]
|
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Missing Service Call
|
||||
description: Service call is missing in Ryujinx.
|
||||
labels: not-implemented
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Service call
|
||||
description: What service call is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Service description
|
||||
description: Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this service.
|
||||
validations:
|
||||
required: true
|
98
.github/workflows/build.yml
vendored
98
.github/workflows/build.yml
vendored
@ -18,10 +18,16 @@ on:
|
||||
- '*.yml'
|
||||
- 'README.md'
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1.0"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.os }} (${{ matrix.configuration }})
|
||||
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
@ -33,7 +39,7 @@ jobs:
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: macOS-latest
|
||||
OS_NAME: MacOS x64
|
||||
OS_NAME: macOS x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: osx-x64
|
||||
RELEASE_ZIP_OS_NAME: osx_x64
|
||||
|
||||
@ -43,47 +49,107 @@ jobs:
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
|
||||
fail-fast: false
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1.0"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
- name: Test
|
||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Publish Ryujinx.Headless.SDL2
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Publish Ryujinx.Ava
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Set executable bit
|
||||
run: |
|
||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
|
||||
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
|
||||
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_sdl2_headless
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_ava
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Debug, Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
172
.github/workflows/flatpak.yml
vendored
Normal file
172
.github/workflows/flatpak.yml
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
name: Flatpak release job
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ryujinx_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
|
||||
concurrency: flatpak-release
|
||||
|
||||
jobs:
|
||||
release:
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||
GIT_COMMITTER_NAME: "RyujinxBot"
|
||||
GIT_COMMITTER_EMAIL: "61127645+RyujinxBot@users.noreply.github.com"
|
||||
RYUJINX_PROJECT_FILE: "src/Ryujinx/Ryujinx.csproj"
|
||||
NUGET_SOURCES_DESTDIR: "nuget-sources"
|
||||
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
path: Ryujinx
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: Ryujinx/global.json
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
working-directory: Ryujinx
|
||||
run: |
|
||||
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: flathub/org.ryujinx.Ryujinx
|
||||
token: ${{ secrets.RYUJINX_BOT_PAT }}
|
||||
submodules: recursive
|
||||
path: flathub
|
||||
|
||||
- name: Install dependencies
|
||||
run: python -m pip install PyYAML lxml
|
||||
|
||||
- name: Restore Nuget packages
|
||||
run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }}
|
||||
|
||||
- name: Generate nuget_sources.json
|
||||
shell: python
|
||||
run: |
|
||||
from pathlib import Path
|
||||
import base64
|
||||
import binascii
|
||||
import json
|
||||
import os
|
||||
|
||||
sources = []
|
||||
|
||||
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
|
||||
name = path.parent.parent.name
|
||||
version = path.parent.name
|
||||
filename = '{}.{}.nupkg'.format(name, version)
|
||||
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
|
||||
|
||||
with path.open() as fp:
|
||||
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
|
||||
|
||||
sources.append({
|
||||
'type': 'file',
|
||||
'url': url,
|
||||
'sha512': sha512,
|
||||
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
|
||||
'dest-filename': filename,
|
||||
})
|
||||
|
||||
with open('flathub/nuget_sources.json', 'w') as fp:
|
||||
json.dump(sources, fp, indent=4)
|
||||
|
||||
- name: Update flatpak metadata
|
||||
id: metadata
|
||||
env:
|
||||
RYUJINX_GIT_HASH: ${{ steps.version_info.outputs.git_hash }}
|
||||
shell: python
|
||||
run: |
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from lxml import etree
|
||||
|
||||
|
||||
# Ensure we don't destroy multiline strings
|
||||
def str_presenter(dumper, data):
|
||||
if len(data.splitlines()) > 1:
|
||||
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
|
||||
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
|
||||
|
||||
|
||||
yaml.representer.SafeRepresenter.add_representer(str, str_presenter)
|
||||
|
||||
yaml_file = "flathub/org.ryujinx.Ryujinx.yml"
|
||||
xml_file = "flathub/org.ryujinx.Ryujinx.appdata.xml"
|
||||
|
||||
with open(yaml_file, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
for source in data["modules"][0]["sources"]:
|
||||
if type(source) is str:
|
||||
continue
|
||||
if (
|
||||
source["type"] == "git"
|
||||
and source["url"] == "https://github.com/Ryujinx/Ryujinx.git"
|
||||
):
|
||||
source["commit"] = os.environ['RYUJINX_GIT_HASH']
|
||||
|
||||
is_same_version = data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] == os.environ['RYUJINX_VERSION']
|
||||
|
||||
with open(os.environ['GITHUB_OUTPUT'], "a") as gh_out:
|
||||
if is_same_version:
|
||||
gh_out.write(f"commit_message=Retry update to {os.environ['RYUJINX_VERSION']}")
|
||||
else:
|
||||
gh_out.write(f"commit_message=Update to {os.environ['RYUJINX_VERSION']}")
|
||||
|
||||
if not is_same_version:
|
||||
data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] = os.environ['RYUJINX_VERSION']
|
||||
|
||||
with open(yaml_file, "w") as f:
|
||||
yaml.safe_dump(data, f, sort_keys=False)
|
||||
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(xml_file, parser)
|
||||
|
||||
root = tree.getroot()
|
||||
|
||||
releases = root.find("releases")
|
||||
|
||||
element = etree.Element("release")
|
||||
element.set("version", os.environ['RYUJINX_VERSION'])
|
||||
element.set("date", datetime.now().date().isoformat())
|
||||
releases.insert(0, element)
|
||||
|
||||
# Ensure 4 spaces
|
||||
etree.indent(root, space=" ")
|
||||
|
||||
with open(xml_file, "wb") as f:
|
||||
f.write(
|
||||
etree.tostring(
|
||||
tree,
|
||||
pretty_print=True,
|
||||
encoding="UTF-8",
|
||||
doctype='<?xml version="1.0" encoding="UTF-8"?>',
|
||||
)
|
||||
)
|
||||
|
||||
- name: Push flatpak update
|
||||
working-directory: flathub
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ steps.metadata.outputs.commit_message }}
|
||||
run: |
|
||||
git config user.name "${{ env.GIT_COMMITTER_NAME }}"
|
||||
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
|
||||
git add .
|
||||
git commit -m "$COMMIT_MESSAGE"
|
||||
git push origin master
|
3
.github/workflows/nightly_pr_comment.yml
vendored
3
.github/workflows/nightly_pr_comment.yml
vendored
@ -7,6 +7,7 @@ jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
@ -65,4 +66,4 @@ jobs:
|
||||
} else {
|
||||
core.info(`Creating a comment`);
|
||||
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
||||
}
|
174
.github/workflows/release.yml
vendored
174
.github/workflows/release.yml
vendored
@ -13,76 +13,116 @@ on:
|
||||
|
||||
concurrency: release
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create tag
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
|
||||
sha: context.sha
|
||||
})
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
name: Release ${{ matrix.OS_NAME }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
OS_NAME: Linux x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: linux-x64
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: windows-latest
|
||||
OS_NAME: Windows x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
run: "mkdir release_output"
|
||||
- name: Publish Windows
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_windows
|
||||
pushd publish_gtk
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_sdl2_headless
|
||||
pushd publish_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_ava
|
||||
pushd publish_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Publish Linux
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_linux
|
||||
pushd publish_gtk
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
pushd publish_sdl2_headless
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
pushd publish_ava
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
shell: bash
|
||||
@ -93,10 +133,78 @@ jobs:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
removeArtifacts: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "publish_ava/*.tar.gz"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
flatpak_release:
|
||||
uses: ./.github/workflows/flatpak.yml
|
||||
needs: release
|
||||
with:
|
||||
ryujinx_version: "1.1.${{ github.run_number }}"
|
||||
secrets: inherit
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -125,6 +125,9 @@ ClientBin/
|
||||
packages/*
|
||||
*.config
|
||||
|
||||
# Include nuget.config
|
||||
!nuget.config
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
@ -167,3 +170,6 @@ launchSettings.json
|
||||
|
||||
# NetCore Publishing Profiles
|
||||
PublishProfiles/
|
||||
|
||||
# Glade backup files
|
||||
*.glade~
|
||||
|
@ -1,6 +0,0 @@
|
||||
namespace ARMeilleure.Decoders;
|
||||
|
||||
interface IOpCode32Exception
|
||||
{
|
||||
int Id { get; }
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Intrinsic : ushort
|
||||
{
|
||||
X86Addpd,
|
||||
X86Addps,
|
||||
X86Addsd,
|
||||
X86Addss,
|
||||
X86Aesdec,
|
||||
X86Aesdeclast,
|
||||
X86Aesenc,
|
||||
X86Aesenclast,
|
||||
X86Aesimc,
|
||||
X86Andnpd,
|
||||
X86Andnps,
|
||||
X86Andpd,
|
||||
X86Andps,
|
||||
X86Blendvpd,
|
||||
X86Blendvps,
|
||||
X86Cmppd,
|
||||
X86Cmpps,
|
||||
X86Cmpsd,
|
||||
X86Cmpss,
|
||||
X86Comisdeq,
|
||||
X86Comisdge,
|
||||
X86Comisdlt,
|
||||
X86Comisseq,
|
||||
X86Comissge,
|
||||
X86Comisslt,
|
||||
X86Crc32,
|
||||
X86Crc32_16,
|
||||
X86Crc32_8,
|
||||
X86Cvtdq2pd,
|
||||
X86Cvtdq2ps,
|
||||
X86Cvtpd2dq,
|
||||
X86Cvtpd2ps,
|
||||
X86Cvtps2dq,
|
||||
X86Cvtps2pd,
|
||||
X86Cvtsd2si,
|
||||
X86Cvtsd2ss,
|
||||
X86Cvtsi2sd,
|
||||
X86Cvtsi2si,
|
||||
X86Cvtsi2ss,
|
||||
X86Cvtss2sd,
|
||||
X86Cvtss2si,
|
||||
X86Divpd,
|
||||
X86Divps,
|
||||
X86Divsd,
|
||||
X86Divss,
|
||||
X86Gf2p8affineqb,
|
||||
X86Haddpd,
|
||||
X86Haddps,
|
||||
X86Insertps,
|
||||
X86Maxpd,
|
||||
X86Maxps,
|
||||
X86Maxsd,
|
||||
X86Maxss,
|
||||
X86Minpd,
|
||||
X86Minps,
|
||||
X86Minsd,
|
||||
X86Minss,
|
||||
X86Movhlps,
|
||||
X86Movlhps,
|
||||
X86Movss,
|
||||
X86Mulpd,
|
||||
X86Mulps,
|
||||
X86Mulsd,
|
||||
X86Mulss,
|
||||
X86Mxcsrmb,
|
||||
X86Mxcsrub,
|
||||
X86Paddb,
|
||||
X86Paddd,
|
||||
X86Paddq,
|
||||
X86Paddw,
|
||||
X86Palignr,
|
||||
X86Pand,
|
||||
X86Pandn,
|
||||
X86Pavgb,
|
||||
X86Pavgw,
|
||||
X86Pblendvb,
|
||||
X86Pclmulqdq,
|
||||
X86Pcmpeqb,
|
||||
X86Pcmpeqd,
|
||||
X86Pcmpeqq,
|
||||
X86Pcmpeqw,
|
||||
X86Pcmpgtb,
|
||||
X86Pcmpgtd,
|
||||
X86Pcmpgtq,
|
||||
X86Pcmpgtw,
|
||||
X86Pmaxsb,
|
||||
X86Pmaxsd,
|
||||
X86Pmaxsw,
|
||||
X86Pmaxub,
|
||||
X86Pmaxud,
|
||||
X86Pmaxuw,
|
||||
X86Pminsb,
|
||||
X86Pminsd,
|
||||
X86Pminsw,
|
||||
X86Pminub,
|
||||
X86Pminud,
|
||||
X86Pminuw,
|
||||
X86Pmovsxbw,
|
||||
X86Pmovsxdq,
|
||||
X86Pmovsxwd,
|
||||
X86Pmovzxbw,
|
||||
X86Pmovzxdq,
|
||||
X86Pmovzxwd,
|
||||
X86Pmulld,
|
||||
X86Pmullw,
|
||||
X86Popcnt,
|
||||
X86Por,
|
||||
X86Pshufb,
|
||||
X86Pshufd,
|
||||
X86Pslld,
|
||||
X86Pslldq,
|
||||
X86Psllq,
|
||||
X86Psllw,
|
||||
X86Psrad,
|
||||
X86Psraw,
|
||||
X86Psrld,
|
||||
X86Psrlq,
|
||||
X86Psrldq,
|
||||
X86Psrlw,
|
||||
X86Psubb,
|
||||
X86Psubd,
|
||||
X86Psubq,
|
||||
X86Psubw,
|
||||
X86Punpckhbw,
|
||||
X86Punpckhdq,
|
||||
X86Punpckhqdq,
|
||||
X86Punpckhwd,
|
||||
X86Punpcklbw,
|
||||
X86Punpckldq,
|
||||
X86Punpcklqdq,
|
||||
X86Punpcklwd,
|
||||
X86Pxor,
|
||||
X86Rcpps,
|
||||
X86Rcpss,
|
||||
X86Roundpd,
|
||||
X86Roundps,
|
||||
X86Roundsd,
|
||||
X86Roundss,
|
||||
X86Rsqrtps,
|
||||
X86Rsqrtss,
|
||||
X86Sha256Msg1,
|
||||
X86Sha256Msg2,
|
||||
X86Sha256Rnds2,
|
||||
X86Shufpd,
|
||||
X86Shufps,
|
||||
X86Sqrtpd,
|
||||
X86Sqrtps,
|
||||
X86Sqrtsd,
|
||||
X86Sqrtss,
|
||||
X86Subpd,
|
||||
X86Subps,
|
||||
X86Subsd,
|
||||
X86Subss,
|
||||
X86Unpckhpd,
|
||||
X86Unpckhps,
|
||||
X86Unpcklpd,
|
||||
X86Unpcklps,
|
||||
X86Vcvtph2ps,
|
||||
X86Vcvtps2ph,
|
||||
X86Vfmadd231ps,
|
||||
X86Vfmadd231sd,
|
||||
X86Vfmadd231ss,
|
||||
X86Vfmsub231sd,
|
||||
X86Vfmsub231ss,
|
||||
X86Vfnmadd231ps,
|
||||
X86Vfnmadd231sd,
|
||||
X86Vfnmadd231ss,
|
||||
X86Vfnmsub231sd,
|
||||
X86Vfnmsub231ss,
|
||||
X86Xorpd,
|
||||
X86Xorps
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
using ARMeilleure.CodeGen.X86;
|
||||
|
||||
namespace ARMeilleure
|
||||
{
|
||||
public static class Optimizations
|
||||
{
|
||||
public static bool FastFP { get; set; } = true;
|
||||
|
||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||
|
||||
public static bool UseSseIfAvailable { get; set; } = true;
|
||||
public static bool UseSse2IfAvailable { get; set; } = true;
|
||||
public static bool UseSse3IfAvailable { get; set; } = true;
|
||||
public static bool UseSsse3IfAvailable { get; set; } = true;
|
||||
public static bool UseSse41IfAvailable { get; set; } = true;
|
||||
public static bool UseSse42IfAvailable { get; set; } = true;
|
||||
public static bool UsePopCntIfAvailable { get; set; } = true;
|
||||
public static bool UseAvxIfAvailable { get; set; } = true;
|
||||
public static bool UseF16cIfAvailable { get; set; } = true;
|
||||
public static bool UseFmaIfAvailable { get; set; } = true;
|
||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||
public static bool UseShaIfAvailable { get; set; } = true;
|
||||
public static bool UseGfniIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
get => HardwareCapabilities.ForceLegacySse;
|
||||
set => HardwareCapabilities.ForceLegacySse = value;
|
||||
}
|
||||
|
||||
internal static bool UseSse => UseSseIfAvailable && HardwareCapabilities.SupportsSse;
|
||||
internal static bool UseSse2 => UseSse2IfAvailable && HardwareCapabilities.SupportsSse2;
|
||||
internal static bool UseSse3 => UseSse3IfAvailable && HardwareCapabilities.SupportsSse3;
|
||||
internal static bool UseSsse3 => UseSsse3IfAvailable && HardwareCapabilities.SupportsSsse3;
|
||||
internal static bool UseSse41 => UseSse41IfAvailable && HardwareCapabilities.SupportsSse41;
|
||||
internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42;
|
||||
internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt;
|
||||
internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
||||
internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c;
|
||||
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
static class DelegateHelper
|
||||
{
|
||||
private const string DelegateTypesAssemblyName = "JitDelegateTypes";
|
||||
|
||||
private static readonly ModuleBuilder _modBuilder;
|
||||
|
||||
private static readonly Dictionary<string, Type> _delegateTypesCache;
|
||||
|
||||
static DelegateHelper()
|
||||
{
|
||||
AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
|
||||
|
||||
_modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
|
||||
|
||||
_delegateTypesCache = new Dictionary<string, Type>();
|
||||
}
|
||||
|
||||
public static Delegate GetDelegate(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
|
||||
Type returnType = info.ReturnType;
|
||||
|
||||
Type delegateType = GetDelegateType(parameters, returnType);
|
||||
|
||||
return Delegate.CreateDelegate(delegateType, info);
|
||||
}
|
||||
|
||||
private static Type GetDelegateType(Type[] parameters, Type returnType)
|
||||
{
|
||||
string key = GetFunctionSignatureKey(parameters, returnType);
|
||||
|
||||
if (!_delegateTypesCache.TryGetValue(key, out Type delegateType))
|
||||
{
|
||||
delegateType = MakeDelegateType(parameters, returnType, key);
|
||||
|
||||
_delegateTypesCache.TryAdd(key, delegateType);
|
||||
}
|
||||
|
||||
return delegateType;
|
||||
}
|
||||
|
||||
private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
|
||||
{
|
||||
string sig = GetTypeName(returnType);
|
||||
|
||||
foreach (Type type in parameters)
|
||||
{
|
||||
sig += '_' + GetTypeName(type);
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
private static string GetTypeName(Type type)
|
||||
{
|
||||
return type.FullName.Replace(".", string.Empty);
|
||||
}
|
||||
|
||||
private const MethodAttributes CtorAttributes =
|
||||
MethodAttributes.RTSpecialName |
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.Public;
|
||||
|
||||
private const TypeAttributes DelegateTypeAttributes =
|
||||
TypeAttributes.Class |
|
||||
TypeAttributes.Public |
|
||||
TypeAttributes.Sealed |
|
||||
TypeAttributes.AnsiClass |
|
||||
TypeAttributes.AutoClass;
|
||||
|
||||
private const MethodImplAttributes ImplAttributes =
|
||||
MethodImplAttributes.Runtime |
|
||||
MethodImplAttributes.Managed;
|
||||
|
||||
private const MethodAttributes InvokeAttributes =
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.NewSlot |
|
||||
MethodAttributes.Virtual;
|
||||
|
||||
private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
|
||||
|
||||
private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
|
||||
{
|
||||
TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
|
||||
|
||||
builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
|
||||
|
||||
builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
|
||||
|
||||
return builder.CreateTypeInfo();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,273 +0,0 @@
|
||||
using ARMeilleure.Instructions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
static class Delegates
|
||||
{
|
||||
public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
|
||||
{
|
||||
if (index >= 0 && index < _delegates.Count)
|
||||
{
|
||||
funcPtr = _delegates.Values[index].FuncPtr; // O(1).
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
funcPtr = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetDelegateFuncPtrByIndex(int index)
|
||||
{
|
||||
if (index < 0 || index >= _delegates.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"({nameof(index)} = {index})");
|
||||
}
|
||||
|
||||
return _delegates.Values[index].FuncPtr; // O(1).
|
||||
}
|
||||
|
||||
public static IntPtr GetDelegateFuncPtr(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
|
||||
{
|
||||
throw new KeyNotFoundException($"({nameof(key)} = {key})");
|
||||
}
|
||||
|
||||
return dlgInfo.FuncPtr;
|
||||
}
|
||||
|
||||
public static int GetDelegateIndex(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
int index = _delegates.IndexOfKey(key); // O(log(n)).
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
throw new KeyNotFoundException($"({nameof(key)} = {key})");
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private static void SetDelegateInfo(MethodInfo info)
|
||||
{
|
||||
string key = GetKey(info);
|
||||
|
||||
Delegate dlg = DelegateHelper.GetDelegate(info);
|
||||
|
||||
_delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key).
|
||||
}
|
||||
|
||||
private static string GetKey(MethodInfo info)
|
||||
{
|
||||
return $"{info.DeclaringType.Name}.{info.Name}";
|
||||
}
|
||||
|
||||
private static readonly SortedList<string, DelegateInfo> _delegates;
|
||||
|
||||
static Delegates()
|
||||
{
|
||||
_delegates = new SortedList<string, DelegateInfo>();
|
||||
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Truncate), new Type[] { typeof(double) }));
|
||||
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Ceiling), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Truncate), new Type[] { typeof(float) }));
|
||||
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
|
||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,40 +3,40 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="Crc32.NET" Version="1.2.0" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||
<PackageVersion Include="DynamicData" Version="7.12.11" />
|
||||
<PackageVersion Include="DynamicData" Version="7.13.8" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageVersion Include="LibHac" Version="0.17.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageVersion Include="LibHac" Version="0.18.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
@ -44,11 +44,10 @@
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
|
||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -40,7 +40,7 @@
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 of those being considered playable.
|
||||
As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
@ -96,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
|
@ -1,123 +0,0 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
{
|
||||
class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private HardwareDeviceSessionOutputBase _realSession;
|
||||
private uint _userChannelCount;
|
||||
|
||||
public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount)
|
||||
{
|
||||
_realSession = realSession;
|
||||
_userChannelCount = userChannelCount;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_realSession.Dispose();
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
return _realSession.GetPlayedSampleCount();
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
{
|
||||
return _realSession.GetVolume();
|
||||
}
|
||||
|
||||
public override void PrepareToClose()
|
||||
{
|
||||
_realSession.PrepareToClose();
|
||||
}
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
_realSession.QueueBuffer(buffer);
|
||||
}
|
||||
|
||||
public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
|
||||
{
|
||||
if (RequestedSampleFormat != SampleFormat.PcmInt16)
|
||||
{
|
||||
throw new NotImplementedException("Downmixing formats other than PCM16 is not supported.");
|
||||
}
|
||||
|
||||
if (samples == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short[] downmixedBufferPCM16;
|
||||
|
||||
ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples);
|
||||
|
||||
if (_userChannelCount == 6)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16);
|
||||
|
||||
if (_realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(downmixedBufferPCM16);
|
||||
}
|
||||
}
|
||||
else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented.");
|
||||
}
|
||||
|
||||
byte[] downmixedBuffer = MemoryMarshal.Cast<short, byte>(downmixedBufferPCM16).ToArray();
|
||||
|
||||
AudioBuffer fakeBuffer = new AudioBuffer
|
||||
{
|
||||
BufferTag = buffer.BufferTag,
|
||||
DataPointer = buffer.DataPointer,
|
||||
DataSize = (ulong)downmixedBuffer.Length
|
||||
};
|
||||
|
||||
bool result = _realSession.RegisterBuffer(fakeBuffer, downmixedBuffer);
|
||||
|
||||
if (result)
|
||||
{
|
||||
buffer.Data = fakeBuffer.Data;
|
||||
buffer.DataSize = fakeBuffer.DataSize;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
_realSession.SetVolume(volume);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
_realSession.Start();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_realSession.Stop();
|
||||
}
|
||||
|
||||
public override void UnregisterBuffer(AudioBuffer buffer)
|
||||
{
|
||||
_realSession.UnregisterBuffer(buffer);
|
||||
}
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
return _realSession.WasBufferFullyConsumed(buffer);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,273 +0,0 @@
|
||||
{
|
||||
"MenuBarFile": "_Fichier",
|
||||
"MenuBarFileOpenFromFile": "_Charger un jeu depuis un fichier",
|
||||
"MenuBarFileOpenUnpacked": "Charger un jeu _extrait",
|
||||
"MenuBarFileOpenEmuFolder": "Ouvrir le dossier Ryujinx",
|
||||
"MenuBarFileOpenLogsFolder": "Ouvrir le dossier de Logs",
|
||||
"MenuBarFileExit": "_Quitter",
|
||||
"MenuBarOptions": "Options",
|
||||
"MenuBarOptionsToggleFullscreen": "Basculer en plein écran",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "Démarrer le jeu en plein écran",
|
||||
"MenuBarOptionsStopEmulation": "Arrêter l'émulation",
|
||||
"MenuBarOptionsSettings": "_Paramètres",
|
||||
"MenuBarOptionsManageUserProfiles": "_Gêrer les profils d'utilisateurs",
|
||||
"MenuBarActions": "_Actions",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simuler une sortie de veille",
|
||||
"MenuBarActionsScanAmiibo": "Scanner un Amiibo",
|
||||
"MenuBarTools": "_Outils",
|
||||
"MenuBarToolsInstallFirmware": "Installer un firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Installer un firmware depuis un fichier XCI ou ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Installer un firmware depuis un dossier",
|
||||
"MenuBarHelp": "Aide",
|
||||
"MenuBarHelpCheckForUpdates": "Vérifier les mises à jour",
|
||||
"MenuBarHelpAbout": "Á propos",
|
||||
"MenuSearch": "Rechercher...",
|
||||
"GameListHeaderFavorite": "Favoris",
|
||||
"GameListHeaderIcon": "Icône",
|
||||
"GameListHeaderApplication": "Application",
|
||||
"GameListHeaderDeveloper": "Développeur",
|
||||
"GameListHeaderVersion": "Version",
|
||||
"GameListHeaderTimePlayed": "Temps de jeu",
|
||||
"GameListHeaderLastPlayed": "Dernière partie",
|
||||
"GameListHeaderFileExtension": "Extension du Fichier",
|
||||
"GameListHeaderFileSize": "Taille du Fichier",
|
||||
"GameListHeaderPath": "Chemin",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Ouvrir le dossier de sauvegarde console",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
||||
"GameListContextMenuManageTitleUpdates": "Gérer les mises à jour",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour",
|
||||
"GameListContextMenuManageDlc": "Gérer les DLC",
|
||||
"GameListContextMenuManageDlcToolTip": "Ouvre la fenêtre de gestion des DLC",
|
||||
"GameListContextMenuOpenModsDirectory": "Ouvrir le dossier des Mods",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods du jeu",
|
||||
"GameListContextMenuCacheManagement": "Gestion des caches",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Purger le PPTC",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Supprime le PPTC du jeu",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Purger le cache des Shaders",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Supprime le cache des shaders du jeu",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Ouvrir le dossier du PPTC",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Ouvre le dossier contenant le PPTC du jeu",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Ouvrir le dossier du cache des shaders",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Ouvre le dossier contenant le cache des shaders du jeu",
|
||||
"GameListContextMenuExtractData": "Extraire les données",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Extrait la section ExeFS du jeu (mise à jour incluse)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Extrait la section RomFS du jeu (mise à jour incluse)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Extrait la section Logo du jeu (mise à jour incluse)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} Jeux chargés",
|
||||
"StatusBarSystemVersion": "Version du Firmware: {0}",
|
||||
"Settings": "Paramètres",
|
||||
"SettingsTabGeneral": "Général",
|
||||
"SettingsTabGeneralGeneral": "Général",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Active Discord Rich Presence",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Vérifier les mises à jour au démarrage",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "Afficher le message de \"Confirmation de fermeture\"",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "Masquer le curseur si inactif",
|
||||
"SettingsTabGeneralGameDirectories": "Dossiers de Jeux",
|
||||
"SettingsTabGeneralAdd": "Ajouter",
|
||||
"SettingsTabGeneralRemove": "Supprimer",
|
||||
"SettingsTabSystem": "Système",
|
||||
"SettingsTabSystemCore": "Core",
|
||||
"SettingsTabSystemSystemRegion": "Région du système:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Japon",
|
||||
"SettingsTabSystemSystemRegionUSA": "USA",
|
||||
"SettingsTabSystemSystemRegionEurope": "Europe",
|
||||
"SettingsTabSystemSystemRegionAustralia": "Australie",
|
||||
"SettingsTabSystemSystemRegionChina": "Chine",
|
||||
"SettingsTabSystemSystemRegionKorea": "Corée",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "Taïwan",
|
||||
"SettingsTabSystemSystemLanguage": "Langue du système:",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "Japonais",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "Américain",
|
||||
"SettingsTabSystemSystemLanguageFrench": "Français",
|
||||
"SettingsTabSystemSystemLanguageGerman": "Allemand",
|
||||
"SettingsTabSystemSystemLanguageItalian": "Italien",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "Espagnol",
|
||||
"SettingsTabSystemSystemLanguageChinese": "Chinois",
|
||||
"SettingsTabSystemSystemLanguageKorean": "Coréen",
|
||||
"SettingsTabSystemSystemLanguageDutch": "Néerlandais",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "Portugais",
|
||||
"SettingsTabSystemSystemLanguageRussian": "Russe",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "Taïwanais",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "Anglais",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "Canadien",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Espagnol latino-américain",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Chinois simplifié",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Chinois traditionnel",
|
||||
"SettingsTabSystemSystemTimeZone": "Fuseau horaire du système:",
|
||||
"SettingsTabSystemSystemTime": "Heure du système:",
|
||||
"SettingsTabSystemEnableVsync": "Activer la VSync",
|
||||
"SettingsTabSystemEnablePptc": "Activer le PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Activer la vérification de l'intégrité du système de fichiers",
|
||||
"SettingsTabSystemAudioBackend": "Bibliothèque Audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)",
|
||||
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant",
|
||||
"SettingsTabGraphics": "Graphique",
|
||||
"SettingsTabGraphicsAPI": "API Graphique",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Activer le cache des shaders",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtrage anisotrope:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "Échelle de résolution:",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "Customisée (Non recommandée)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Native (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "Format:",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Écran étiré",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Options développeur",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de dump des shaders:",
|
||||
"SettingsTabGraphicsFeatures": "Fonctionnalités & Améliorations",
|
||||
"SettingsTabLogging": "Journaux",
|
||||
"SettingsTabLoggingLogging": "Journaux",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Activer la sauvegarde des journaux vers un fichier",
|
||||
"SettingsTabLoggingEnableStubLogs": "Activer les journaux stub",
|
||||
"SettingsTabLoggingEnableInfoLogs": "Activer les journaux d'informations",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Activer les journaux d'avertissements",
|
||||
"SettingsTabLoggingEnableErrorLogs": "Activer les journaux d'erreurs",
|
||||
"SettingsTabLoggingEnableGuestLogs": "Activer les journaux du programme simulé",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Aucun",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erreur",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentissements",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tout",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug",
|
||||
"SettingsTabInput": "Contrôles",
|
||||
"SettingsTabInputEnableDockedMode": "Active le mode station d'accueil",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
||||
"SettingsButtonSave": "Enregistrer",
|
||||
"SettingsButtonClose": "Fermer",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Annuler",
|
||||
"SettingsButtonApply": "Appliquer",
|
||||
"ControllerSettingsPlayer": "Joueur",
|
||||
"ControllerSettingsPlayer1": "Joueur 1",
|
||||
"ControllerSettingsPlayer2": "Joueur 2",
|
||||
"ControllerSettingsPlayer3": "Joueur 3",
|
||||
"ControllerSettingsPlayer4": "Joueur 4",
|
||||
"ControllerSettingsPlayer5": "Joueur 5",
|
||||
"ControllerSettingsPlayer6": "Joueur 6",
|
||||
"ControllerSettingsPlayer7": "Joueur 7",
|
||||
"ControllerSettingsPlayer8": "Joueur 8",
|
||||
"ControllerSettingsHandheld": "Portable",
|
||||
"ControllerSettingsInputDevice": "Périphériques",
|
||||
"ControllerSettingsRefresh": "Actualiser",
|
||||
"ControllerSettingsDeviceDisabled": "Désactivé",
|
||||
"ControllerSettingsControllerType": "Type de Controleur",
|
||||
"ControllerSettingsControllerTypeHandheld": "Portable",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "JoyCon Joints",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon Gauche",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon Droite",
|
||||
"ControllerSettingsProfile": "Profil",
|
||||
"ControllerSettingsProfileDefault": "Défaut",
|
||||
"ControllerSettingsLoad": "Charger",
|
||||
"ControllerSettingsAdd": "Ajouter",
|
||||
"ControllerSettingsRemove": "Supprimer",
|
||||
"ControllerSettingsButtons": "Boutons",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Croix Directionnelle",
|
||||
"ControllerSettingsDPadUp": "Haut",
|
||||
"ControllerSettingsDPadDown": "Bas",
|
||||
"ControllerSettingsDPadLeft": "Gauche",
|
||||
"ControllerSettingsDPadRight": "Droite",
|
||||
"ControllerSettingsLStick": "Joystick Gauche",
|
||||
"ControllerSettingsLStickButton": "Bouton",
|
||||
"ControllerSettingsLStickUp": "Haut",
|
||||
"ControllerSettingsLStickDown": "Bas",
|
||||
"ControllerSettingsLStickLeft": "Gauche",
|
||||
"ControllerSettingsLStickRight": "Droite",
|
||||
"ControllerSettingsLStickStick": "Joystick",
|
||||
"ControllerSettingsLStickInvertXAxis": "Inverser l'axe X",
|
||||
"ControllerSettingsLStickInvertYAxis": "Inverser l'axe Y",
|
||||
"ControllerSettingsLStickDeadzone": "Zone morte:",
|
||||
"ControllerSettingsRStick": "Joystick Droit",
|
||||
"ControllerSettingsRStickButton": "Bouton",
|
||||
"ControllerSettingsRStickUp": "Haut",
|
||||
"ControllerSettingsRStickDown": "Bas",
|
||||
"ControllerSettingsRStickLeft": "Gauche",
|
||||
"ControllerSettingsRStickRight": "Droite",
|
||||
"ControllerSettingsRStickStick": "Joystick",
|
||||
"ControllerSettingsRStickInvertXAxis": "Inverser l'axe X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Inverser l'axe Y",
|
||||
"ControllerSettingsRStickDeadzone": "Zone morte:",
|
||||
"ControllerSettingsTriggers": "Gachettes",
|
||||
"ControllerSettingsTriggersLeft": "Gachettes Gauche",
|
||||
"ControllerSettingsTriggersRight": "Gachettes Droite",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Boutons Gachettes Gauche",
|
||||
"ControllerSettingsTriggersButtonsRight": "Boutons Gachettes Droite",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "Boutons Gauche",
|
||||
"ControllerSettingsExtraButtonsRight": "Boutons Droite",
|
||||
"ControllerSettingsMisc": "Divers",
|
||||
"ControllerSettingsTriggerThreshold": "Seuil de gachettes:",
|
||||
"ControllerSettingsMotion": "Mouvements",
|
||||
"ControllerSettingsConfigureGeneral": "Configurer",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Utiliser un capteur de mouvements CemuHook",
|
||||
"ControllerSettingsMotionControllerSlot": "Contrôleur ID:",
|
||||
"ControllerSettingsMotionMirrorInput": "Inverser les contrôles",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "JoyCon Droit ID:",
|
||||
"ControllerSettingsMotionServerHost": "Addresse du Server:",
|
||||
"ControllerSettingsMotionGyroSensitivity": "Sensibilitée du gyroscope:",
|
||||
"ControllerSettingsMotionGyroDeadzone": "Zone morte du gyroscope:",
|
||||
"ControllerSettingsSave": "Enregistrer",
|
||||
"ControllerSettingsClose": "Fermer",
|
||||
"UserProfilesSelectedUserProfile": "Choisir un profil utilisateur:",
|
||||
"UserProfilesSaveProfileName": "Enregistrer le nom du profil",
|
||||
"UserProfilesChangeProfileImage": "Changer l'image du profil",
|
||||
"UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:",
|
||||
"UserProfilesAddNewProfile": "Ajouter un nouveau profil",
|
||||
"UserProfilesDeleteSelectedProfile": "Supprimer le profil sélectionné",
|
||||
"UserProfilesClose": "Fermer",
|
||||
"ProfileImageSelectionTitle": "Sélection de l'image du profil",
|
||||
"ProfileImageSelectionHeader": "Choisir l'image du profil",
|
||||
"ProfileImageSelectionNote": "Vous pouvez importer une image de profil personnalisée ou sélectionner un avatar à partir du firmware",
|
||||
"ProfileImageSelectionImportImage": "Importer une image",
|
||||
"ProfileImageSelectionSelectAvatar": "Choisir un avatar du firmware",
|
||||
"InputDialogTitle": "Fenêtre d'entrée de texte",
|
||||
"InputDialogOk": "OK",
|
||||
"InputDialogCancel": "Annuler",
|
||||
"InputDialogAddNewProfileTitle": "Choisir un nom de profil",
|
||||
"InputDialogAddNewProfileHeader": "Merci d'entrer un nom de profil",
|
||||
"InputDialogAddNewProfileSubtext": "(Longueur max.: {0})",
|
||||
"AvatarChoose": "Choisir",
|
||||
"AvatarSetBackgroundColor": "Choisir une couleur de fond",
|
||||
"AvatarClose": "Fermer",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
}
|
@ -1,597 +0,0 @@
|
||||
{
|
||||
"MenuBarFileOpenApplet": "Apri applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'editor Mii in modalità standalone",
|
||||
"SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse",
|
||||
"SettingsTabSystemMemoryManagerMode": "Modalità di gestione della memoria:",
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "Software",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "Host (veloce)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "Host Unchecked (più veloce, non sicura)",
|
||||
"MenuBarFile": "_File",
|
||||
"MenuBarFileOpenFromFile": "_Carica applicazione da un file",
|
||||
"MenuBarFileOpenUnpacked": "Carica _gioco estratto",
|
||||
"MenuBarFileOpenEmuFolder": "Apri cartella di Ryujinx",
|
||||
"MenuBarFileOpenLogsFolder": "Apri cartella dei logs",
|
||||
"MenuBarFileExit": "_Esci",
|
||||
"MenuBarOptions": "Opzioni",
|
||||
"MenuBarOptionsToggleFullscreen": "Schermo intero",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "Avvia i giochi a schermo intero",
|
||||
"MenuBarOptionsStopEmulation": "Ferma emulazione",
|
||||
"MenuBarOptionsSettings": "_Impostazioni",
|
||||
"MenuBarOptionsManageUserProfiles": "_Gestisci i profili utente",
|
||||
"MenuBarActions": "_Azioni",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simula messaggio Wake-up",
|
||||
"MenuBarActionsScanAmiibo": "Scansiona un Amiibo",
|
||||
"MenuBarTools": "_Strumenti",
|
||||
"MenuBarToolsInstallFirmware": "Installa firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Installa un firmware da file XCI o ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Installa un firmare da una cartella",
|
||||
"MenuBarHelp": "Aiuto",
|
||||
"MenuBarHelpCheckForUpdates": "Controlla aggiornamenti",
|
||||
"MenuBarHelpAbout": "Informazioni",
|
||||
"MenuSearch": "Cerca...",
|
||||
"GameListHeaderFavorite": "Pref",
|
||||
"GameListHeaderIcon": "Icona",
|
||||
"GameListHeaderApplication": "Nome",
|
||||
"GameListHeaderDeveloper": "Sviluppatore",
|
||||
"GameListHeaderVersion": "Versione",
|
||||
"GameListHeaderTimePlayed": "Tempo di gioco",
|
||||
"GameListHeaderLastPlayed": "Giocato l'ultima volta",
|
||||
"GameListHeaderFileExtension": "Estensione",
|
||||
"GameListHeaderFileSize": "Dimensione file",
|
||||
"GameListHeaderPath": "Percorso",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Apri la cartella dispositivo dell'utente",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Apri la cartella BCAT dell'utente",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione",
|
||||
"GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
||||
"GameListContextMenuManageDlc": "Gestici DLC",
|
||||
"GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC",
|
||||
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mod",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mod dell'applicazione",
|
||||
"GameListContextMenuCacheManagement": "Gestione della cache",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Pulisci shader cache",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la shader cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Apri cartella PPTC",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Apre la cartella che contiene la PPTC cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Apri cartella shader cache",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Apre la cartella che contiene la shader cache dell'applicazione",
|
||||
"GameListContextMenuExtractData": "Estrai dati",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Estrae la sezione ExeFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Estrae la sezione RomFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Estrae la sezione Logo dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} Giochi caricati",
|
||||
"StatusBarSystemVersion": "Versione di sistema: {0}",
|
||||
"Settings": "Impostazioni",
|
||||
"SettingsTabGeneral": "Interfaccia utente",
|
||||
"SettingsTabGeneralGeneral": "Generali",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Attiva Discord Rich Presence",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Controlla aggiornamenti all'avvio",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "Mostra dialogo \"Conferma Uscita\"",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "Nascondi cursore inattivo",
|
||||
"SettingsTabGeneralGameDirectories": "Cartelle dei giochi",
|
||||
"SettingsTabGeneralAdd": "Aggiungi",
|
||||
"SettingsTabGeneralRemove": "Rimuovi",
|
||||
"SettingsTabSystem": "Sistema",
|
||||
"SettingsTabSystemCore": "Core",
|
||||
"SettingsTabSystemSystemRegion": "Regione del sistema:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Giappone",
|
||||
"SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America",
|
||||
"SettingsTabSystemSystemRegionEurope": "Europa",
|
||||
"SettingsTabSystemSystemRegionAustralia": "Australia",
|
||||
"SettingsTabSystemSystemRegionChina": "Cina",
|
||||
"SettingsTabSystemSystemRegionKorea": "Corea",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "Taiwan",
|
||||
"SettingsTabSystemSystemLanguage": "Lingua del sistema:",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "Giapponese",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano",
|
||||
"SettingsTabSystemSystemLanguageFrench": "Francese",
|
||||
"SettingsTabSystemSystemLanguageGerman": "Tedesco",
|
||||
"SettingsTabSystemSystemLanguageItalian": "Italiano",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "Spagnolo",
|
||||
"SettingsTabSystemSystemLanguageChinese": "Cinese",
|
||||
"SettingsTabSystemSystemLanguageKorean": "Coreano",
|
||||
"SettingsTabSystemSystemLanguageDutch": "Olandese",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "Portoghese",
|
||||
"SettingsTabSystemSystemLanguageRussian": "Russo",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "Taiwanese",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "Inglese britannico",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "Francese canadese",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale",
|
||||
"SettingsTabSystemSystemTimeZone": "Fuso orario del sistema:",
|
||||
"SettingsTabSystemSystemTime": "Data e ora del sistema:",
|
||||
"SettingsTabSystemEnableVsync": "Attiva VSync",
|
||||
"SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS",
|
||||
"SettingsTabSystemAudioBackend": "Backend audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Possono causare instabilità)",
|
||||
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti",
|
||||
"SettingsTabGraphics": "Grafica",
|
||||
"SettingsTabGraphicsAPI": "API Grafiche",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Attiva Shader Cache",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotropico:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "Scala della risoluzione:",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "Personalizzata (Non raccomandata)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "Rapporto d'aspetto:",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Adatta alla finestra",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Opzioni da sviluppatore",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Percorso di dump degli shaders:",
|
||||
"SettingsTabLogging": "Log",
|
||||
"SettingsTabLoggingLogging": "Log",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Salva i log su file",
|
||||
"SettingsTabLoggingEnableStubLogs": "Attiva Stub Logs",
|
||||
"SettingsTabLoggingEnableInfoLogs": "Attiva Info Logs",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Attiva Warning Logs",
|
||||
"SettingsTabLoggingEnableErrorLogs": "Attiva Error Logs",
|
||||
"SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs",
|
||||
"SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nessuno",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errore",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Rallentamenti",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tutto",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug",
|
||||
"SettingsTabInput": "Input",
|
||||
"SettingsTabInputEnableDockedMode": "Attiva modalità TV",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
||||
"SettingsButtonSave": "Salva",
|
||||
"SettingsButtonClose": "Chiudi",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Cancella",
|
||||
"SettingsButtonApply": "Applica",
|
||||
"ControllerSettingsPlayer": "Giocatore",
|
||||
"ControllerSettingsPlayer1": "Giocatore 1",
|
||||
"ControllerSettingsPlayer2": "Giocatore 2",
|
||||
"ControllerSettingsPlayer3": "Giocatore 3",
|
||||
"ControllerSettingsPlayer4": "Giocatore 4",
|
||||
"ControllerSettingsPlayer5": "Giocatore 5",
|
||||
"ControllerSettingsPlayer6": "Giocatore 6",
|
||||
"ControllerSettingsPlayer7": "Giocatore 7",
|
||||
"ControllerSettingsPlayer8": "Giocatore 8",
|
||||
"ControllerSettingsHandheld": "Portatile",
|
||||
"ControllerSettingsInputDevice": "Dispositivo di input",
|
||||
"ControllerSettingsRefresh": "Ricarica",
|
||||
"ControllerSettingsDeviceDisabled": "Disabilitato",
|
||||
"ControllerSettingsControllerType": "Tipo di controller",
|
||||
"ControllerSettingsControllerTypeHandheld": "Portatile",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "Coppia di JoyCon",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon sinistro",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon destro",
|
||||
"ControllerSettingsProfile": "Profilo",
|
||||
"ControllerSettingsProfileDefault": "Predefinito",
|
||||
"ControllerSettingsLoad": "Carica",
|
||||
"ControllerSettingsAdd": "Aggiungi",
|
||||
"ControllerSettingsRemove": "Rimuovi",
|
||||
"ControllerSettingsButtons": "Pulsanti",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Croce direzionale",
|
||||
"ControllerSettingsDPadUp": "Su",
|
||||
"ControllerSettingsDPadDown": "Giù",
|
||||
"ControllerSettingsDPadLeft": "Sinistra",
|
||||
"ControllerSettingsDPadRight": "Destra",
|
||||
"ControllerSettingsLStick": "Stick sinistro",
|
||||
"ControllerSettingsLStickButton": "Pulsante",
|
||||
"ControllerSettingsLStickUp": "Su",
|
||||
"ControllerSettingsLStickDown": "Giù",
|
||||
"ControllerSettingsLStickLeft": "Sinistra",
|
||||
"ControllerSettingsLStickRight": "Destra",
|
||||
"ControllerSettingsLStickStick": "Stick",
|
||||
"ControllerSettingsLStickInvertXAxis": "Inverti stick X",
|
||||
"ControllerSettingsLStickInvertYAxis": "Inverti stick Y",
|
||||
"ControllerSettingsLStickDeadzone": "Zona morta:",
|
||||
"ControllerSettingsRStick": "Stick destro",
|
||||
"ControllerSettingsRStickButton": "Pulsante",
|
||||
"ControllerSettingsRStickUp": "Su",
|
||||
"ControllerSettingsRStickDown": "Giù",
|
||||
"ControllerSettingsRStickLeft": "Sinistra",
|
||||
"ControllerSettingsRStickRight": "Destra",
|
||||
"ControllerSettingsRStickStick": "Stick",
|
||||
"ControllerSettingsRStickInvertXAxis": "Inverti stick X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Inverti stick Y",
|
||||
"ControllerSettingsRStickDeadzone": "Zona morta:",
|
||||
"ControllerSettingsTriggersLeft": "Grilletto sinistro",
|
||||
"ControllerSettingsTriggersRight": "Grilletto destro",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Pulsante dorsale sinistro",
|
||||
"ControllerSettingsTriggersButtonsRight": "Pulsante dorsale destro",
|
||||
"ControllerSettingsTriggers": "Grilletti",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "Tasto sinitro",
|
||||
"ControllerSettingsExtraButtonsRight": "Tasto destro",
|
||||
"ControllerSettingsMisc": "Varie",
|
||||
"ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:",
|
||||
"ControllerSettingsMotion": "Movimento",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook",
|
||||
"ControllerSettingsMotionControllerSlot": "Slot del controller:",
|
||||
"ControllerSettingsMotionMirrorInput": "Input specchiato",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "Slot JoyCon destro:",
|
||||
"ControllerSettingsMotionServerHost": "Server:",
|
||||
"ControllerSettingsMotionGyroSensitivity": "Sensibilità del giroscopio:",
|
||||
"ControllerSettingsMotionGyroDeadzone": "Zona morta del giroscopio:",
|
||||
"ControllerSettingsSave": "Salva",
|
||||
"ControllerSettingsClose": "Chiudi",
|
||||
"UserProfilesSelectedUserProfile": "Profilo utente selezionato:",
|
||||
"UserProfilesSaveProfileName": "Salva nome del profilo",
|
||||
"UserProfilesChangeProfileImage": "Cambia immagine profilo",
|
||||
"UserProfilesAvailableUserProfiles": "Profili utente disponibili:",
|
||||
"UserProfilesAddNewProfile": "Aggiungi nuovo profilo",
|
||||
"UserProfilesDeleteSelectedProfile": "Elimina il profilo selezionato",
|
||||
"UserProfilesClose": "Chiudi",
|
||||
"ProfileImageSelectionTitle": "Selezione dell'immagine profilo",
|
||||
"ProfileImageSelectionHeader": "Scegli un'immagine profilo",
|
||||
"ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware del sistema",
|
||||
"ProfileImageSelectionImportImage": "Importa file immagine",
|
||||
"ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware",
|
||||
"InputDialogTitle": "Input Dialog",
|
||||
"InputDialogOk": "OK",
|
||||
"InputDialogCancel": "Annulla",
|
||||
"InputDialogAddNewProfileTitle": "Scegli il nome profilo",
|
||||
"InputDialogAddNewProfileHeader": "Digita un nome profilo",
|
||||
"InputDialogAddNewProfileSubtext": "(Lunghezza massima: {0})",
|
||||
"AvatarChoose": "Scegli",
|
||||
"AvatarSetBackgroundColor": "Imposta colore di sfondo",
|
||||
"AvatarClose": "Chiudi",
|
||||
"ControllerSettingsLoadProfileToolTip": "Carica profilo",
|
||||
"ControllerSettingsAddProfileToolTip": "Aggiungi profilo",
|
||||
"ControllerSettingsRemoveProfileToolTip": "Rimuovi profilo",
|
||||
"ControllerSettingsSaveProfileToolTip": "Salva profilo",
|
||||
"MenuBarFileToolsTakeScreenshot": "Fai uno screenshot",
|
||||
"MenuBarFileToolsHideUi": "Nascondi Ui",
|
||||
"GameListContextMenuToggleFavorite": "Preferito",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "Segna il gioco come preferito",
|
||||
"SettingsTabGeneralTheme": "Tema",
|
||||
"SettingsTabGeneralThemeCustomTheme": "Percorso del tema personalizzato",
|
||||
"SettingsTabGeneralThemeBaseStyle": "Modalità",
|
||||
"SettingsTabGeneralThemeBaseStyleDark": "Scura",
|
||||
"SettingsTabGeneralThemeBaseStyleLight": "Chiara",
|
||||
"SettingsTabGeneralThemeEnableCustomTheme": "Attiva tema personalizzato",
|
||||
"ButtonBrowse": "Sfoglia",
|
||||
"ControllerSettingsConfigureGeneral": "Configura",
|
||||
"ControllerSettingsRumble": "Vibrazione",
|
||||
"ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte",
|
||||
"ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole",
|
||||
"DialogMessageSaveNotAvailableMessage": "Non ci sono dati di salvataggio per {0} [{1:x16}]",
|
||||
"DialogMessageSaveNotAvailableCreateSaveMessage": "Vuoi creare dei dati di salvataggio per questo gioco?",
|
||||
"DialogConfirmationTitle": "Ryujinx - Conferma",
|
||||
"DialogUpdaterTitle": "Ryujinx - Updater",
|
||||
"DialogErrorTitle": "Ryujinx - Errore",
|
||||
"DialogWarningTitle": "Ryujinx - Avviso",
|
||||
"DialogExitTitle": "Ryujinx - Uscita",
|
||||
"DialogErrorMessage": "Ryujinx ha riscontrato un problema",
|
||||
"DialogExitMessage": "Sei sicuro di voler chiudere Ryujinx?",
|
||||
"DialogExitSubMessage": "Tutti i dati non salvati andranno persi!",
|
||||
"DialogMessageCreateSaveErrorMessage": "C'è stato un errore durante la creazione dei dati di salvataggio: {0}",
|
||||
"DialogMessageFindSaveErrorMessage": "C'è stato un errore durante la ricerca dei dati di salvataggio: {0}",
|
||||
"FolderDialogExtractTitle": "Scegli una cartella in cui estrarre",
|
||||
"DialogNcaExtractionMessage": "Estrazione della sezione {0} da {1}...",
|
||||
"DialogNcaExtractionTitle": "Ryujinx - Estrattore sezione NCA",
|
||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "L'estrazione è fallita. L'NCA principale non era presente nel file selezionato.",
|
||||
"DialogNcaExtractionCheckLogErrorMessage": "L'estrazione è fallita. Leggi il log per più informazioni.",
|
||||
"DialogNcaExtractionSuccessMessage": "Estrazione completata con successo.",
|
||||
"DialogUpdaterConvertFailedMessage": "La conversione dell'attuale versione di Ryujinx è fallita.",
|
||||
"DialogUpdaterCancelUpdateMessage": "Annullando l'aggiornamento!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "Stai già usando la versione più recente di Ryujinx!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Si è verificato un errore nel tentativo di ottenere informazioni da Github Release. Questo può verificarsi se una nuova release è in compilazione su GitHub Actions. Riprova tra qualche minuto.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "La conversione della versione di Ryujinx ricevuta da Github Release è fallita.",
|
||||
"DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...",
|
||||
"DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...",
|
||||
"DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...",
|
||||
"DialogUpdaterAddingFilesMessage": "Aggiunta del nuovo aggiornamento...",
|
||||
"DialogUpdaterCompleteMessage": "Aggiornamento completato!",
|
||||
"DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?",
|
||||
"DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!",
|
||||
"DialogUpdaterArchNotSupportedSubMessage": "(Solo sistemi x64 sono supportati!)",
|
||||
"DialogUpdaterNoInternetMessage": "Non sei connesso ad Internet!",
|
||||
"DialogUpdaterNoInternetSubMessage": "Verifica di avere una connessione ad Internet funzionante!",
|
||||
"DialogUpdaterDirtyBuildMessage": "Non puoi aggiornare una Dirty build di Ryujinx!",
|
||||
"DialogUpdaterDirtyBuildSubMessage": "Scarica Ryujinx da https://ryujinx.org/ se stai cercando una versione supportata.",
|
||||
"DialogRestartRequiredMessage": "Riavvio richiesto",
|
||||
"DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.",
|
||||
"DialogThemeRestartSubMessage": "Vuoi riavviare?",
|
||||
"DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})",
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito ad installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "Nessun firmware installato",
|
||||
"DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato",
|
||||
"DialogOpenSettingsWindowLabel": "Apri finestra delle impostazioni",
|
||||
"DialogControllerAppletTitle": "Applet del controller",
|
||||
"DialogMessageDialogErrorExceptionMessage": "Errore nella visualizzazione del Message Dialog: {0}",
|
||||
"DialogSoftwareKeyboardErrorExceptionMessage": "Errore nella visualizzazione della tastiera software: {0}",
|
||||
"DialogErrorAppletErrorExceptionMessage": "Errore nella visualizzazione dell'ErrorApplet Dialog: {0}",
|
||||
"DialogUserErrorDialogMessage": "{0}: {1}",
|
||||
"DialogUserErrorDialogInfoMessage": "\nPer più informazioni su come risolvere questo errore, segui la nostra guida all'installazione.",
|
||||
"DialogUserErrorDialogTitle": "Errore di Ryujinx ({0})",
|
||||
"DialogAmiiboApiTitle": "Amiibo API",
|
||||
"DialogAmiiboApiFailFetchMessage": "Si è verificato un errore durante il recupero delle informazioni dall'API.",
|
||||
"DialogAmiiboApiConnectErrorMessage": "Impossibile connettersi al server Amiibo API. Il servizio potrebbe essere fuori uso o potresti dover verificare che la tua connessione internet sia online.",
|
||||
"DialogProfileInvalidProfileErrorMessage": "Il profilo {0} è incompatibile con l'attuale sistema di configurazione input.",
|
||||
"DialogProfileDefaultProfileOverwriteErrorMessage": "Il profilo predefinito non può essere sovrascritto",
|
||||
"DialogProfileDeleteProfileTitle": "Eliminazione profilo",
|
||||
"DialogProfileDeleteProfileMessage": "Quest'azione è irreversibile, sei sicuro di voler continuare?",
|
||||
"DialogWarning": "Avviso",
|
||||
"DialogPPTCDeletionMessage": "Stai per eliminare la PPTC cache per :\n\n{0}\n\nSei sicuro di voler proseguire?",
|
||||
"DialogPPTCDeletionErrorMessage": "Errore nell'eliminazione della PPTC cache a {0}: {1}",
|
||||
"DialogShaderDeletionMessage": "Stai per eliminare la Shader cache per :\n\n{0}\n\nSei sicuro di voler proseguire?",
|
||||
"DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}",
|
||||
"DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore",
|
||||
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un ID titolo valido",
|
||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware del sistema valido non è stato trovato in {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallTitle": "Installa firmware {0}",
|
||||
"DialogFirmwareInstallerFirmwareInstallMessage": "La versione del sistema {0} sarà installata.",
|
||||
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nQuesta sostituirà l'attuale versione di sistema {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?",
|
||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...",
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione del sistema {0} è stata installata.",
|
||||
"DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato",
|
||||
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. File errato: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Hai abilitato lo shader dumping, che è progettato per essere usato solo dagli sviluppatori.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare lo shader dumping. Vuoi disabilitare lo shader dumping adesso?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "Un gioco è già stato caricato",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "Ferma l'emulazione o chiudi l'emulatore prima di avviare un altro gioco.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "Il file specificato non contiene un aggiornamento per il titolo selezionato!",
|
||||
"DialogSettingsBackendThreadingWarningTitle": "Avviso - Backend Threading",
|
||||
"DialogSettingsBackendThreadingWarningMessage": "Ryujinx deve essere riavviato dopo aver cambiato questa opzione per applicarla completamente. A seconda della tua piattaforma, potrebbe essere necessario disabilitare manualmente il multithreading del driver quando usi quello di Ryujinx.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "Funzionalità",
|
||||
"SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading",
|
||||
"CommonAuto": "Auto",
|
||||
"CommonOff": "Spento",
|
||||
"CommonOn": "Acceso",
|
||||
"InputDialogYes": "Si",
|
||||
"InputDialogNo": "No",
|
||||
"DialogProfileInvalidProfileNameErrorMessage": "Il nome del file contiene caratteri non validi. Riprova.",
|
||||
"MenuBarOptionsPauseEmulation": "Pausa",
|
||||
"MenuBarOptionsResumeEmulation": "Riprendi",
|
||||
"AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.",
|
||||
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.",
|
||||
"AboutPatreonUrlTooltipMessage": "Clicca per aprire la pagina Patreon di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutRyujinxAboutTitle": "Informazioni:",
|
||||
"AboutRyujinxAboutContent": "Ryujinx è un emulatore per la Nintendo Switch™.\nPer favore supportaci su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.",
|
||||
"AboutRyujinxMaintainersTitle": "Mantenuto da:",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei Contributors nel tuo browser predefinito.",
|
||||
"AboutRyujinxSupprtersTitle": "Supportato su Patreon da:",
|
||||
"AmiiboSeriesLabel": "Serie Amiibo",
|
||||
"AmiiboCharacterLabel": "Personaggio",
|
||||
"AmiiboScanButtonLabel": "Scannerizza",
|
||||
"AmiiboOptionsShowAllLabel": "Mostra tutti gli amiibo",
|
||||
"AmiiboOptionsUsRandomTagLabel": "Hack: Usa un tag uuid casuale",
|
||||
"DlcManagerTableHeadingEnabledLabel": "Abilitato",
|
||||
"DlcManagerTableHeadingTitleIdLabel": "Title ID",
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Percorso del contenitore",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Percorso completo",
|
||||
"DlcManagerRemoveAllButton": "Rimuovi tutti",
|
||||
"MenuBarOptionsChangeLanguage": "Cambia lingua",
|
||||
"CommonSort": "Ordina",
|
||||
"CommonShowNames": "Mostra nomi",
|
||||
"CommonFavorite": "Preferito",
|
||||
"OrderAscending": "Crescente",
|
||||
"OrderDescending": "Decrescente",
|
||||
"SettingsTabGraphicsFeatures": "Funzionalità & Miglioramenti",
|
||||
"ErrorWindowTitle": "Finestra errore",
|
||||
"ToggleDiscordTooltip": "Attiva o disattiva Discord Rich Presence",
|
||||
"AddGameDirBoxTooltip": "Inserisci la directory di un gioco per aggiungerlo alla lista",
|
||||
"AddGameDirTooltip": "Aggiungi la directory di un gioco alla lista",
|
||||
"RemoveGameDirTooltip": "Rimuovi la directory di gioco selezionata",
|
||||
"CustomThemeCheckTooltip": "Attiva o disattiva temi personalizzati nella GUI",
|
||||
"CustomThemePathTooltip": "Percorso al tema GUI personalizzato",
|
||||
"CustomThemeBrowseTooltip": "Sfoglia per cercare un tema GUI personalizzato",
|
||||
"DockModeToggleTooltip": "Attiva o disabilta modalità TV",
|
||||
"DirectKeyboardTooltip": "Attiva o disattiva \"il supporto all'accesso diretto alla tastiera (HID)\" (Fornisce l'accesso ai giochi alla tua tastiera come dispositivo di immissione del testo)",
|
||||
"DirectMouseTooltip": "Attiva o disattiva \"il supporto all'accesso diretto al mouse (HID)\" (Fornisce l'accesso ai giochi al tuo mouse come dispositivo di puntamento)",
|
||||
"RegionTooltip": "Cambia regione di sistema",
|
||||
"LanguageTooltip": "Cambia lingua di sistema",
|
||||
"TimezoneTooltip": "Cambia fuso orario di sistema",
|
||||
"TimeTooltip": "Cambia data e ora di sistema",
|
||||
"VSyncToggleTooltip": "Attiva o disattiva sincronizzazione verticale",
|
||||
"PptcToggleTooltip": "Attiva o disattiva PPTC",
|
||||
"FsIntegrityToggleTooltip": "Attiva controlli d'integrità sui file dei contenuti di gioco",
|
||||
"AudioBackendTooltip": "Cambia backend audio",
|
||||
"MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.",
|
||||
"MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.",
|
||||
"MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.",
|
||||
"MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.",
|
||||
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GiB A 6GiB",
|
||||
"IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti",
|
||||
"GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading",
|
||||
"GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.",
|
||||
"ShaderCacheToggleTooltip": "Attiva o disattiva la Shader Cache",
|
||||
"ResolutionScaleTooltip": "Scala della risoluzione applicata ai render targets applicabili",
|
||||
"ResolutionScaleEntryTooltip": "Scala della risoluzione in virgola mobile, come 1,5. Le scale non integrali hanno maggiori probabilità di causare problemi o crash.",
|
||||
"AnisotropyTooltip": "Livello del filtro anisotropico (imposta su Auto per usare il valore richiesto dal gioco)",
|
||||
"AspectRatioTooltip": "Rapporto d'aspetto applicato alla finestra del renderer.",
|
||||
"ShaderDumpPathTooltip": "Percorso di dump Graphics Shaders",
|
||||
"FileLogTooltip": "Attiva o disattiva il logging su file",
|
||||
"StubLogTooltip": "Attiva messaggi stub log",
|
||||
"InfoLogTooltip": "Attiva messaggi info log",
|
||||
"WarnLogTooltip": "Attiva messaggi warning log",
|
||||
"ErrorLogTooltip": "Attiva messaggi error log",
|
||||
"TraceLogTooltip": "Attiva messaggi trace log",
|
||||
"GuestLogTooltip": "Attiva messaggi guest log",
|
||||
"FileAccessLogTooltip": "Attiva messaggi file access log",
|
||||
"FSAccessLogModeTooltip": "Attiva output FS access log alla console. Le modalità possibili sono 0-3",
|
||||
"DeveloperOptionTooltip": "Usa con attenzione",
|
||||
"OpenGlLogLevel": "Richiede livelli di log appropriati abilitati",
|
||||
"DebugLogTooltip": "Attiva messaggi debug log",
|
||||
"LoadApplicationFileTooltip": "Apri un file explorer per scegliere un file compatibile Switch da caricare",
|
||||
"LoadApplicationFolderTooltip": "Apri un file explorer per scegliere un file compatibile Switch, applicazione sfusa da caricare",
|
||||
"OpenRyujinxFolderTooltip": "Apri la cartella del filesystem di Ryujinx",
|
||||
"OpenRyujinxLogsTooltip": "Apre la cartella dove vengono scritti i log",
|
||||
"ExitTooltip": "Esci da Ryujinx",
|
||||
"OpenSettingsTooltip": "Apri finestra delle impostazioni",
|
||||
"OpenProfileManagerTooltip": "Apri la finestra di gestione dei profili utente",
|
||||
"StopEmulationTooltip": "Ferma l'emulazione del gioco attuale e torna alla selezione dei giochi",
|
||||
"CheckUpdatesTooltip": "Controlla la presenza di aggiornamenti di Ryujinx",
|
||||
"OpenAboutTooltip": "Apri finestra delle informazioni",
|
||||
"GridSize": "Dimensione griglia",
|
||||
"GridSizeTooltip": "Cambia la dimensione dei riquardi della griglia",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portoghese Brasiliano",
|
||||
"AboutRyujinxContributorsButtonHeader": "Vedi tutti i Contributors",
|
||||
"SettingsTabSystemAudioVolume": "Volume: ",
|
||||
"AudioVolumeTooltip": "Cambia volume audio",
|
||||
"SettingsTabSystemEnableInternetAccess": "Attiva Guest Internet Access",
|
||||
"EnableInternetAccessTooltip": "Attiva il guest Internet access. Se abilitato, l'applicazione si comporterà come se la console Switch emulata fosse collegata a Internet. Si noti che in alcuni casi, le applicazioni possono comunque accedere a Internet anche con questa opzione disabilitata",
|
||||
"GameListContextMenuManageCheatToolTip": "Gestisci Cheats",
|
||||
"GameListContextMenuManageCheat": "Gestisci Cheats",
|
||||
"ControllerSettingsStickRange": "Raggio:",
|
||||
"DialogStopEmulationTitle": "Ryujinx - Ferma emulazione",
|
||||
"DialogStopEmulationMessage": "Sei sicuro di voler fermare l'emulazione?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "Audio",
|
||||
"SettingsTabNetwork": "Rete",
|
||||
"SettingsTabNetworkConnection": "Connessione di rete",
|
||||
"SettingsTabCpuCache": "Cache CPU",
|
||||
"SettingsTabCpuMemory": "Memoria CPU",
|
||||
"DialogUpdaterFlatpakNotSupportedMessage": "Per favore aggiorna Ryujinx via FlatHub.",
|
||||
"UpdaterDisabledWarningTitle": "Updater disabilitato!",
|
||||
"GameListContextMenuOpenSdModsDirectory": "Apri cartella delle mods Atmosphere",
|
||||
"GameListContextMenuOpenSdModsDirectoryToolTip": "Apre la cartella aternativa di atmosphere che contiene le mods dell'applicazione",
|
||||
"ControllerSettingsRotate90": "Ruota in senso orario di 90°",
|
||||
"IconSize": "Dimensioni icona",
|
||||
"IconSizeTooltip": "Cambia le dimensioni dell'icona di un gioco",
|
||||
"MenuBarOptionsShowConsole": "Mostra console",
|
||||
"ShaderCachePurgeError" : "Errore nella pulizia della shader cache a {0}: {1}",
|
||||
"UserErrorNoKeys": "Chiavi non trovate",
|
||||
"UserErrorNoFirmware": "Firmware non trovato",
|
||||
"UserErrorFirmwareParsingFailed": "Errori di analisi del firmware",
|
||||
"UserErrorApplicationNotFound": "Applicazione non trovata",
|
||||
"UserErrorUnknown": "Errore sconosciuto",
|
||||
"UserErrorUndefined": "Errore non definito",
|
||||
"UserErrorNoKeysDescription": "Ryujinx non è riuscito a trovare il file 'prod.keys'",
|
||||
"UserErrorNoFirmwareDescription": "Ryujinx non è riuscito a trovare alcun firmware installato",
|
||||
"UserErrorFirmwareParsingFailedDescription": "Ryujinx non è riuscito ad analizzare il firmware. Questo di solito è causato da chiavi non aggiornate.",
|
||||
"UserErrorApplicationNotFoundDescription": "Ryujinx non è riuscito a trovare un'applicazione valida al percorso specificato.",
|
||||
"UserErrorUnknownDescription": "Si è verificato un errore sconosciuto!",
|
||||
"UserErrorUndefinedDescription": "Si è verificato un errore sconosciuto! Non dovrebbe succedere, per favore contatta uno sviluppatore!",
|
||||
"OpenSetupGuideMessage": "Apri la guida all'installazione",
|
||||
"NoUpdate": "Nessun aggiornamento",
|
||||
"TitleUpdateVersionLabel": "Versione {0} - {1}",
|
||||
"RyujinxInfo": "Ryujinx - Info",
|
||||
"RyujinxConfirm": "Ryujinx - Conferma",
|
||||
"FileDialogAllTypes": "Tutti i tipi",
|
||||
"Never": "Mai",
|
||||
"SwkbdMinCharacters": "Non può avere meno di {0} caratteri",
|
||||
"SwkbdMinRangeCharacters": "Può avere da {0} a {1} caratteri",
|
||||
"SoftwareKeyboard": "Tastiera software",
|
||||
"DialogControllerAppletMessagePlayerRange": "L'applicazione richiede {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.",
|
||||
"DialogControllerAppletMessage": "L'applicazione richiede esattamente {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.",
|
||||
"DialogControllerAppletDockModeSet": "Modalità TV attivata. Neanche portatile è valida.\n\n",
|
||||
"UpdaterRenaming": "Rinominazione dei vecchi files...",
|
||||
"UpdaterRenameFailed": "L'updater non è riuscito a rinominare il file: {0}",
|
||||
"UpdaterAddingFiles": "Aggiunta nuovi files...",
|
||||
"UpdaterExtracting": "Estrazione aggiornamento...",
|
||||
"UpdaterDownloading": "Download aggiornamento...",
|
||||
"Game": "Gioco",
|
||||
"Docked": "TV",
|
||||
"Handheld": "Portatile",
|
||||
"ConnectionError": "Errore di connessione.",
|
||||
"AboutPageDeveloperListMore": "{0} e altri ancora...",
|
||||
"ApiError": "Errore dell'API.",
|
||||
"LoadingHeading": "Caricamento di {0}",
|
||||
"CompilingPPTC": "Compilazione PTC",
|
||||
"CompilingShaders": "Compilazione Shaders",
|
||||
"AllKeyboards": "Tutte le tastiere",
|
||||
"OpenFileDialogTitle": "Seleziona un file supportato da aprire",
|
||||
"OpenFolderDialogTitle": "Seleziona una cartella con un gioco estratto",
|
||||
"AllSupportedFormats": "Tutti i formati supportati",
|
||||
"RyujinxUpdater": "Ryujinx Updater",
|
||||
"SettingsTabHotkeys": "Tasti di scelta rapida",
|
||||
"SettingsTabHotkeysHotkeys": "Tasti di scelta rapida",
|
||||
"SettingsTabHotkeysToggleVsyncHotkey": "VSync:",
|
||||
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
|
||||
"SettingsTabHotkeysShowUiHotkey": "Mostra UI:",
|
||||
"SettingsTabHotkeysPauseHotkey": "Metti in pausa:",
|
||||
"SettingsTabHotkeysToggleMuteHotkey": "Muta:",
|
||||
"ControllerMotionTitle": "Impostazioni dei sensori di movimento",
|
||||
"ControllerRumbleTitle": "Impostazioni di vibrazione",
|
||||
"SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema",
|
||||
"SettingsXamlThemeFile" : "File del tema xaml",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:",
|
||||
"AvatarWindowTitle": "Gestisci account - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Sconosciuto",
|
||||
"Usage": "Utilizzo",
|
||||
"Writable": "Scrivibile",
|
||||
"SelectDlcDialogTitle": "Seleziona file dei DLC",
|
||||
"SelectUpdateDialogTitle": "Seleziona file di aggiornamento",
|
||||
"UserProfileWindowTitle": "Gestisci profili degli utenti",
|
||||
"CheatWindowTitle": "Gestisci cheat dei giochi",
|
||||
"DlcWindowTitle": "Gestisci DLC dei giochi",
|
||||
"UpdateWindowTitle": "Gestisci aggiornamenti dei giochi",
|
||||
"CheatWindowHeading": "Cheat disponibiili per {0} [{1}]",
|
||||
"DlcWindowHeading": "DLC disponibili per {0} [{1}]",
|
||||
"UserProfilesEditProfile": "Modifica selezionati",
|
||||
"Cancel": "Annulla",
|
||||
"Save": "Salva",
|
||||
"Discard": "Scarta",
|
||||
"UserProfilesSetProfileImage": "Imposta immagine profilo",
|
||||
"UserProfileEmptyNameError": "È richiesto un nome",
|
||||
"UserProfileNoImageError": "Dev'essere impostata un'immagine profilo",
|
||||
"GameUpdateWindowHeading": "Aggiornamenti disponibili per {0} [{1}]",
|
||||
"UserProfilesName": "Name:",
|
||||
"UserProfilesUserId": "User Id:",
|
||||
"SettingsTabGraphicsBackend": "Backend grafica",
|
||||
"SettingsTabGraphicsBackendTooltip": "Backend grafica da usare",
|
||||
"SettingsEnableTextureRecompression": "Abilita Ricompressione Texture",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Comprime alcune texture per ridurre l'utilizzo della VRAM.\n\nL'utilizzo è consigliato con GPU con meno di 4GB di VRAM.\n\nLascia su OFF se non sei sicuro.",
|
||||
"SettingsTabGraphicsPreferredGpu": "GPU preferita",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Seleziona la scheda grafica che verrà usata con la backend grafica Vulkan.\n\nNon influenza la GPU che userà OpenGL.\n\nImposta la GPU contrassegnata come \"dGPU\" se non sei sicuro. Se non ce n'è una, lascia intatta quest'impostazione.",
|
||||
"SettingsAppRequiredRestartMessage": "È richiesto un riavvio di Ryujinx",
|
||||
"SettingsGpuBackendRestartMessage": "Le impostazioni della backend grafica o della GPU sono state modificate. Questo richiederà un riavvio perché le modifiche siano applicate",
|
||||
"SettingsGpuBackendRestartSubMessage": "Vuoi riavviare ora?",
|
||||
"RyujinxUpdaterMessage": "Vuoi aggiornare Ryujinx all'ultima versione?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Aumentare il volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Diminuire il volume:",
|
||||
"VolumeShort": "Vol"
|
||||
}
|
@ -1,495 +0,0 @@
|
||||
{
|
||||
"MenuBarFileOpenApplet": "애플릿 열기",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기",
|
||||
"SettingsTabInputDirectMouseAccess": "직접 마우스 액세스",
|
||||
"SettingsTabSystemMemoryManagerMode": "메모리 관리자 모드 :",
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "소프트웨어",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "호스트 (빠른)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "호스트가 확인되지 않음 (가장 빠르고 안전하지 않은)",
|
||||
"MenuBarFile": "_파일",
|
||||
"MenuBarFileOpenFromFile": "_서류철음에서 애플리케이션 로드",
|
||||
"MenuBarFileOpenUnpacked": "_압축을 푼 게임 로드",
|
||||
"MenuBarFileOpenEmuFolder": "Ryujinx 폴더 열기",
|
||||
"MenuBarFileOpenLogsFolder": "로그 폴더 열기",
|
||||
"MenuBarFileExit": "_그만두",
|
||||
"MenuBarOptions": "옵션",
|
||||
"MenuBarOptionsToggleFullscreen": "전체 화면 전환",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "전체 화면 모드에서 게임 열기",
|
||||
"MenuBarOptionsStopEmulation": "에뮬레이션 중지",
|
||||
"MenuBarOptionsSettings": "_조절",
|
||||
"MenuBarOptionsManageUserProfiles": "사용자 프로필 _관리",
|
||||
"MenuBarActions": "_행위",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "깨우기 명령어 시뮬레이션",
|
||||
"MenuBarActionsScanAmiibo": "Amiibo 스캔",
|
||||
"MenuBarTools": "_도구",
|
||||
"MenuBarToolsInstallFirmware": "펌웨어 설치",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "XCI 또는 ZIP에서 펌웨어 설치",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "디렉토리에서 펌웨어 설치",
|
||||
"MenuBarHelp": "돕다",
|
||||
"MenuBarHelpCheckForUpdates": "업데이트 확인",
|
||||
"MenuBarHelpAbout": "통지",
|
||||
"MenuSearch": "찾다···",
|
||||
"GameListHeaderFavorite": "즐겨찾기",
|
||||
"GameListHeaderIcon": "상",
|
||||
"GameListHeaderApplication": "이름",
|
||||
"GameListHeaderDeveloper": "개발자",
|
||||
"GameListHeaderVersion": "버전",
|
||||
"GameListHeaderTimePlayed": "플레이 시간",
|
||||
"GameListHeaderLastPlayed": "해본 마지막",
|
||||
"GameListHeaderFileExtension": "파일 확장자",
|
||||
"GameListHeaderFileSize": "파일 크기",
|
||||
"GameListHeaderPath": "파일 경로",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "사용자 저장 폴더 열기",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "응용 프로그램의 사용자 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "사용자 장치 폴더 열기",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "응용 프로그램의 장치 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "사용자의 BCAT 폴더 열기",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "응용 프로그램의 BCAT 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuManageTitleUpdates": "타이틀 업데이트 관리s",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기",
|
||||
"GameListContextMenuManageDlc": "DLC 관리",
|
||||
"GameListContextMenuManageDlcToolTip": "DLC 관리 창 열기",
|
||||
"GameListContextMenuOpenModsDirectory": "모드 디렉토리 열기",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "응용 프로그램의 모드가들 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuCacheManagement": "캐시 관리",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "PPTC 캐시 제거",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "응용 프로그램 PPTC 캐시 삭제",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "셰이더 캐시 제거",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "애플리케이션 셰이더 캐시를 삭제합니다.",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "PPTC 디렉토리 열기",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "응용 프로그램 PPTC 캐시가 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "셰이더 캐시 디렉토리 열기",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "응용 프로그램 셰이더 캐시가 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuExtractData": "데이터 추출",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "애플리케이션의 현재 구성에서 ExeFS 추출 (업데이트 포함)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "애플리케이션의 현재 구성에서 RomFS 추출 (업데이트 포함)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "애플리케이션의 현재 구성에서 로고 섹션 추출 (업데이트 포함)",
|
||||
"StatusBarGamesLoaded": "로드된 {0}/{1}개의 게임",
|
||||
"StatusBarSystemVersion": "시스템 버전 : {0}",
|
||||
"Settings": "조절",
|
||||
"SettingsTabGeneral": "사용자 인터페이스",
|
||||
"SettingsTabGeneralGeneral": "일반",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Discord Rich Presence 활성화",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "열 때 업데이트 확인",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "\"종료 확인\" 대화 상자 표시",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "유휴 상태에서 커서 숨기기",
|
||||
"SettingsTabGeneralGameDirectories": "게임 디렉토리들",
|
||||
"SettingsTabGeneralAdd": "추가하다",
|
||||
"SettingsTabGeneralRemove": "제거하다",
|
||||
"SettingsTabSystem": "체계",
|
||||
"SettingsTabSystemCore": "핵심",
|
||||
"SettingsTabSystemSystemRegion": "시스템 영역 :",
|
||||
"SettingsTabSystemSystemRegionJapan": "일본",
|
||||
"SettingsTabSystemSystemRegionUSA": "미국",
|
||||
"SettingsTabSystemSystemRegionEurope": "유럽",
|
||||
"SettingsTabSystemSystemRegionAustralia": "호주",
|
||||
"SettingsTabSystemSystemRegionChina": "중국",
|
||||
"SettingsTabSystemSystemRegionKorea": "한국",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "대만",
|
||||
"SettingsTabSystemSystemLanguage": "시스템 언어 :",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "일본어",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "영어(미국)",
|
||||
"SettingsTabSystemSystemLanguageFrench": "프랑스어",
|
||||
"SettingsTabSystemSystemLanguageGerman": "독일어",
|
||||
"SettingsTabSystemSystemLanguageItalian": "이탈리아어",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "스페인어",
|
||||
"SettingsTabSystemSystemLanguageChinese": "중국어",
|
||||
"SettingsTabSystemSystemLanguageKorean": "한국어",
|
||||
"SettingsTabSystemSystemLanguageDutch": "네덜란드 어",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "포르투갈어",
|
||||
"SettingsTabSystemSystemLanguageRussian": "러시아어",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "대만어",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "영어(영국)",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "프랑스어(캐나다)",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "스페인어(라틴 아메리카)",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "중국어 간체",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "중국어 번체",
|
||||
"SettingsTabSystemSystemTimeZone": "시스템 시간대 :",
|
||||
"SettingsTabSystemSystemTime": "시스템 시간 :",
|
||||
"SettingsTabSystemEnableVsync": "수직 동기화 사용",
|
||||
"SettingsTabSystemEnablePptc": "PPTC(Profiled Persistent Translation Cache) 활성화",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "FS 무결성 검사 활성화",
|
||||
"SettingsTabSystemAudioBackend": "오디오 백엔드 :",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "해킹",
|
||||
"SettingsTabSystemHacksNote": " (불안정을 일으킬 수 있음)",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GiB로 확장",
|
||||
"SettingsTabSystemIgnoreMissingServices": "누락된 서비스 무시",
|
||||
"SettingsTabGraphics": "제도법",
|
||||
"SettingsTabGraphicsAPI": "그래픽 API",
|
||||
"SettingsTabGraphicsEnableShaderCache": "셰이더 캐시 활성화",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "이방성 필터링 :",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "자동적 인",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "해상도 스케일 :",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "사용자 지정(권장하지 않음)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "기본 (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "종횡비 :",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "창에 맞게 늘리기",
|
||||
"SettingsTabGraphicsDeveloperOptions": "개발자 옵션",
|
||||
"SettingsTabGraphicsShaderDumpPath": "그래픽 쉐이더 덤프 경로 :",
|
||||
"SettingsTabLogging": "로깅",
|
||||
"SettingsTabLoggingLogging": "로깅",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "파일에 로깅 활성화",
|
||||
"SettingsTabLoggingEnableStubLogs": "스텁 로그 켜기 ",
|
||||
"SettingsTabLoggingEnableInfoLogs": "정보 로그 켜기",
|
||||
"SettingsTabLoggingEnableWarningLogs": "경고 로그 켜기",
|
||||
"SettingsTabLoggingEnableErrorLogs": "오류 로그 켜기",
|
||||
"SettingsTabLoggingEnableGuestLogs": "게스트 로그 켜기",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :",
|
||||
"SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "없음",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "오류",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "감속",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "모두",
|
||||
"SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용",
|
||||
"SettingsTabInput": "입력",
|
||||
"SettingsTabInputEnableDockedMode": "도킹 모드 활성화",
|
||||
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
||||
"SettingsButtonSave": "구하다",
|
||||
"SettingsButtonClose": "출구",
|
||||
"SettingsButtonOk": "좋아",
|
||||
"SettingsButtonCancel": "취소",
|
||||
"SettingsButtonApply": "적용하다",
|
||||
"ControllerSettingsPlayer": "플레이어",
|
||||
"ControllerSettingsPlayer1": "플레이어 1",
|
||||
"ControllerSettingsPlayer2": "플레이어 2",
|
||||
"ControllerSettingsPlayer3": "플레이어 3",
|
||||
"ControllerSettingsPlayer4": "플레이어 4",
|
||||
"ControllerSettingsPlayer5": "플레이어 5",
|
||||
"ControllerSettingsPlayer6": "플레이어 6",
|
||||
"ControllerSettingsPlayer7": "플레이어 7",
|
||||
"ControllerSettingsPlayer8": "플레이어 8",
|
||||
"ControllerSettingsHandheld": "휴대용",
|
||||
"ControllerSettingsInputDevice": "입력 장치",
|
||||
"ControllerSettingsRefresh": "새로 고치다",
|
||||
"ControllerSettingsDeviceDisabled": "장애가있는",
|
||||
"ControllerSettingsControllerType": "컨트롤러 유형",
|
||||
"ControllerSettingsControllerTypeHandheld": "휴대용",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "JoyCon 페어",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon 왼쪽",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon 오른쪽",
|
||||
"ControllerSettingsProfile": "프로필",
|
||||
"ControllerSettingsProfileDefault": "기본",
|
||||
"ControllerSettingsLoad": "짐",
|
||||
"ControllerSettingsAdd": "추가하다",
|
||||
"ControllerSettingsRemove": "제거하다",
|
||||
"ControllerSettingsButtons": "버튼",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Directional Pad",
|
||||
"ControllerSettingsDPadUp": "위로",
|
||||
"ControllerSettingsDPadDown": "아래에",
|
||||
"ControllerSettingsDPadLeft": "왼쪽",
|
||||
"ControllerSettingsDPadRight": "오른쪽",
|
||||
"ControllerSettingsLStick": "왼쪽 스틱",
|
||||
"ControllerSettingsLStickButton": "단추",
|
||||
"ControllerSettingsLStickUp": "위로",
|
||||
"ControllerSettingsLStickDown": "아래에",
|
||||
"ControllerSettingsLStickLeft": "왼쪽",
|
||||
"ControllerSettingsLStickRight": "오른쪽",
|
||||
"ControllerSettingsLStickStick": "막대",
|
||||
"ControllerSettingsLStickInvertXAxis": "스틱 X축 반전",
|
||||
"ControllerSettingsLStickInvertYAxis": "스틱 Y축 반전",
|
||||
"ControllerSettingsLStickDeadzone": "데드 존 :",
|
||||
"ControllerSettingsRStick": "오른쪽 스틱",
|
||||
"ControllerSettingsRStickButton": "단추",
|
||||
"ControllerSettingsRStickUp": "위로",
|
||||
"ControllerSettingsRStickDown": "아래에",
|
||||
"ControllerSettingsRStickLeft": "왼쪽",
|
||||
"ControllerSettingsRStickRight": "오른쪽",
|
||||
"ControllerSettingsRStickStick": "Stick",
|
||||
"ControllerSettingsRStickInvertXAxis": "스틱 X축 반전",
|
||||
"ControllerSettingsRStickInvertYAxis": "스틱 Y축 반전",
|
||||
"ControllerSettingsRStickDeadzone": "데드 존 :",
|
||||
"ControllerSettingsTriggersLeft": "왼쪽 트리거",
|
||||
"ControllerSettingsTriggersRight": "오른쪽 트리거",
|
||||
"ControllerSettingsTriggersButtonsLeft": "트리거 버튼 왼쪽",
|
||||
"ControllerSettingsTriggersButtonsRight": "트리거 버튼 오른쪽",
|
||||
"ControllerSettingsTriggers": "방아쇠",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "왼쪽 버튼",
|
||||
"ControllerSettingsExtraButtonsRight": "버튼 오른쪽",
|
||||
"ControllerSettingsMisc": "여러 가지 잡다한",
|
||||
"ControllerSettingsTriggerThreshold": "트리거 임계값 :",
|
||||
"ControllerSettingsMotion": "운동",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "CemuHook 호환 모션 사용",
|
||||
"ControllerSettingsMotionControllerSlot": "컨트롤러 슬롯 :",
|
||||
"ControllerSettingsMotionMirrorInput": "미러 입력",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "오른쪽 JoyCon 슬롯 :",
|
||||
"ControllerSettingsMotionServerHost": "서버 호스트 :",
|
||||
"ControllerSettingsMotionGyroSensitivity": "자이로 감도 :",
|
||||
"ControllerSettingsMotionGyroDeadzone": "자이로 데드존 :",
|
||||
"ControllerSettingsSave": "구하다",
|
||||
"ControllerSettingsClose": "출구",
|
||||
"UserProfilesSelectedUserProfile": "선택한 사용자 프로필 :",
|
||||
"UserProfilesSaveProfileName": "프로필 이름 저장",
|
||||
"UserProfilesChangeProfileImage": "프로필 이미지 변경",
|
||||
"UserProfilesAvailableUserProfiles": "사용 가능한 사용자 프로필 :",
|
||||
"UserProfilesAddNewProfile": "새 프로필 추가",
|
||||
"UserProfilesDeleteSelectedProfile": "선택한 프로필 삭제",
|
||||
"UserProfilesClose": "출구",
|
||||
"ProfileImageSelectionTitle": "프로필 이미지 선택",
|
||||
"ProfileImageSelectionHeader": "이미지 선택",
|
||||
"ProfileImageSelectionNote": "사용자 정의 프로필 이미지를 사용하거나 시스템 펌웨어에서 하나를 선택할 수 있습니다",
|
||||
"ProfileImageSelectionImportImage": "이미지 파일 가져오기",
|
||||
"ProfileImageSelectionSelectAvatar": "펌웨어 아바타 선택",
|
||||
"InputDialogTitle": "입력 대화 상자",
|
||||
"InputDialogOk": "확인",
|
||||
"InputDialogCancel": "취소",
|
||||
"InputDialogAddNewProfileTitle": "프로필 이름 선택",
|
||||
"InputDialogAddNewProfileHeader": "프로필 이름을 입력하세요",
|
||||
"InputDialogAddNewProfileSubtext": "최대 길이 : {0})",
|
||||
"AvatarChoose": "선택하다",
|
||||
"AvatarSetBackgroundColor": "배경색 설정",
|
||||
"AvatarClose": "출구",
|
||||
"ControllerSettingsLoadProfileToolTip": "프로필 로드",
|
||||
"ControllerSettingsAddProfileToolTip": "프로필 추가",
|
||||
"ControllerSettingsRemoveProfileToolTip": "프로필 제거",
|
||||
"ControllerSettingsSaveProfileToolTip": "프로필 저장",
|
||||
"MenuBarFileToolsTakeScreenshot": "스크린 샷을 찍다",
|
||||
"MenuBarFileToolsHideUi": "사용자 인터페이스 숨기기",
|
||||
"GameListContextMenuToggleFavorite": "즐겨찾기 설정",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "이 게임이 즐겨찾기인지 여부를 전환합니다",
|
||||
"SettingsTabGeneralTheme": "테마",
|
||||
"SettingsTabGeneralThemeCustomTheme": "사용자 정의 테마 경로",
|
||||
"SettingsTabGeneralThemeBaseStyle": "기본 스타일",
|
||||
"SettingsTabGeneralThemeBaseStyleDark": "어두운",
|
||||
"SettingsTabGeneralThemeBaseStyleLight": "빛",
|
||||
"SettingsTabGeneralThemeEnableCustomTheme": "사용자 정의 테마 활성화",
|
||||
"ButtonBrowse": "검색",
|
||||
"ControllerSettingsConfigureGeneral": "션 구성",
|
||||
"ControllerSettingsRumble": "하인 좌석",
|
||||
"ControllerSettingsRumbleStrongMultiplier": "강력한 럼블 배율기",
|
||||
"ControllerSettingsRumbleWeakMultiplier": "약한 럼블 승수",
|
||||
"DialogMessageSaveNotAvailableMessage": "에 대한 세이브 데이터가 없습니다 {0} [{1:x16}]",
|
||||
"DialogMessageSaveNotAvailableCreateSaveMessage": "이 게임의 세이브 데이터를 생성하시겠습니까?",
|
||||
"DialogConfirmationTitle": "Ryujinx - 확인",
|
||||
"DialogUpdaterTitle": "Ryujinx - 업데이터",
|
||||
"DialogErrorTitle": "Ryujinx - 오류",
|
||||
"DialogWarningTitle": "Ryujinx - 경고",
|
||||
"DialogExitTitle": "Ryujinx - 출구",
|
||||
"DialogErrorMessage": "Ryujinx에 오류가 발생했습니다",
|
||||
"DialogExitMessage": "Ryujinx를 종료하시겠습니까?",
|
||||
"DialogExitSubMessage": "저장하지 않은 모든 데이터는 손실됩니다!",
|
||||
"DialogMessageCreateSaveErrorMessage": "지정된 세이브 데이터를 작성하는 중에 오류가 발생했습니다 : {0}",
|
||||
"DialogMessageFindSaveErrorMessage": "지정된 저장 데이터를 찾는 중에 오류가 발생했습니다 : {0}",
|
||||
"FolderDialogExtractTitle": "추출할 폴더 선택",
|
||||
"DialogNcaExtractionMessage": "{1}에서 섹션 {0} 추출···",
|
||||
"DialogNcaExtractionTitle": "Ryujinx - NCA 섹션 추출기",
|
||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "추출 실패. 선택한 파일에 기본 NCA가 없습니다.",
|
||||
"DialogNcaExtractionCheckLogErrorMessage": "추출 실패. 자세한 내용은 로그 파일을 읽으십시오.",
|
||||
"DialogNcaExtractionSuccessMessage": "추출이 성공적으로 완료되었습니다.",
|
||||
"DialogUpdaterConvertFailedMessage": "현재 Ryujinx 버전을 변환하지 못했습니다.",
|
||||
"DialogUpdaterCancelUpdateMessage": "업데이트 취소 중!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "이미 최신 버전의 Ryujinx를 사용하고 있습니다!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Github 릴리스에서 릴리스 정보를 가져오는 중에 오류가 발생했습니다. 이는 GitHub Actions에서 새 릴리스를 컴파일하는 경우 발생할 수 있습니다. 몇 분 후에 다시 시도하십시오.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "Github Release에서 받은 Ryujinx 버전을 변환하지 못했습니다.",
|
||||
"DialogUpdaterDownloadingMessage": "업데이트 다운로드 중···",
|
||||
"DialogUpdaterExtractionMessage": "업데이트 추출···",
|
||||
"DialogUpdaterRenamingMessage": "업데이트 이름 바꾸기···",
|
||||
"DialogUpdaterAddingFilesMessage": "새 업데이트 추가···",
|
||||
"DialogUpdaterCompleteMessage": "업데이트 완료!",
|
||||
"DialogUpdaterRestartMessage": "지금 Ryujinx를 다시 시작하시겠습니까?",
|
||||
"DialogUpdaterArchNotSupportedMessage": "지원되는 시스템 아키텍처를 실행하고 있지 않습니다!",
|
||||
"DialogUpdaterArchNotSupportedSubMessage": "(x86 시스템만 지원됩니다!)",
|
||||
"DialogUpdaterNoInternetMessage": "인터넷에 연결되어 있지 않습니다!",
|
||||
"DialogUpdaterNoInternetSubMessage": "인터넷 연결이 작동하는지 확인하십시오!",
|
||||
"DialogUpdaterDirtyBuildMessage": "Ryujinx의 더러운 빌드는 업데이트할 수 없습니다!",
|
||||
"DialogUpdaterDirtyBuildSubMessage": "지원되는 버전을 찾고 있다면 https://ryujinx.org/에서 Ryujinx를 다운로드하십시오.",
|
||||
"DialogRestartRequiredMessage": "재시작 필요",
|
||||
"DialogThemeRestartMessage": "테마가 저장되었습니다. 테마를 적용하려면 다시 시작해야 합니다.",
|
||||
"DialogThemeRestartSubMessage": "다시 시작하시겠습니까?",
|
||||
"DialogFirmwareInstallEmbeddedMessage": "이 게임에 내장된 펌웨어를 설치하시겠습니까? (펌웨어 {0})",
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "설치된 펌웨어를 찾을 수 없지만 Ryujinx는 제공된 게임에서 펌웨어 {0} 설치할 수 있었습니다.\n이제 에뮬레이터가 시작됩니다.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "펌웨어가 설치되지 않았습니다",
|
||||
"DialogFirmwareInstalledMessage": "펌웨어 {0} 설치되었습니다.",
|
||||
"DialogOpenSettingsWindowLabel": "설정 창 열기",
|
||||
"DialogControllerAppletTitle": "컨트롤러 애플릿",
|
||||
"DialogMessageDialogErrorExceptionMessage": "메시지 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogSoftwareKeyboardErrorExceptionMessage": "소프트웨어 키보드를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogErrorAppletErrorExceptionMessage": "ErrorApplet 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogUserErrorDialogMessage": "{0}: {1}",
|
||||
"DialogUserErrorDialogInfoMessage": "\n이 오류를 수정하는 방법에 대한 자세한 내용은 설정 가이드를 따르십시오",
|
||||
"DialogUserErrorDialogTitle": "Ryuijnx의 오류 ({0})",
|
||||
"DialogAmiiboApiTitle": "Amiibo API",
|
||||
"DialogAmiiboApiFailFetchMessage": "API에서 정보를 가져오는 동안 오류가 발생했습니다.",
|
||||
"DialogAmiiboApiConnectErrorMessage": "Amiibo API 서버에 연결할 수 없습니다. 서비스가 다운되었거나 인터넷 연결이 오프라인인지 확인해야 할 수 있습니다.",
|
||||
"DialogProfileInvalidProfileErrorMessage": "프로필 AAA는 현재 입력 구성 시스템과 호환되지 않습니다.",
|
||||
"DialogProfileDefaultProfileOverwriteErrorMessage": "기본 프로필을 덮어쓸 수 없습니다",
|
||||
"DialogProfileDeleteProfileTitle": "프로필 삭제",
|
||||
"DialogProfileDeleteProfileMessage": "이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?",
|
||||
"DialogWarning": "경고",
|
||||
"DialogPPTCDeletionMessage": "{0}에\n\n 대한 PPTC 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?",
|
||||
"DialogPPTCDeletionErrorMessage": "{0} : {1}에서 PPTC 캐시를 제거하는 동안 오류가 발생했습니다.",
|
||||
"DialogShaderDeletionMessage": "{0}에\n\n 대한 셰이더 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?",
|
||||
"DialogShaderDeletionErrorMessage": "{0} : {1}에서 셰이더 캐시를 제거하는 동안 오류가 발생했습니다.",
|
||||
"DialogRyujinxErrorMessage": "Ryujinx에 오류가 발생했습니다",
|
||||
"DialogInvalidTitleIdErrorMessage": "UI 오류 : 선택한 게임에 유효한 제목 ID가 없습니다",
|
||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "{0}에서 유효한 시스템 펌웨어를 찾을 수 없습니다.",
|
||||
"DialogFirmwareInstallerFirmwareInstallTitle": "펌웨어 {0} 설치",
|
||||
"DialogFirmwareInstallerFirmwareInstallMessage": "시스템 버전 {0}가 설치되려고 합니다",
|
||||
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n이것은 현재 설치된 버전 {0}를 대체합니다.",
|
||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n계속하시겠습니까?",
|
||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "펌웨어 설치···",
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "시스템 버전 {0}가 성공적으로 설치되었습니다.",
|
||||
"DialogUserProfileDeletionWarningMessage": "선택한 프로필이 삭제되면 사용 가능한 다른 프로필이 없습니다",
|
||||
"DialogUserProfileDeletionConfirmMessage": "선택한 프로필을 삭제하시겠습니까",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "저장하시겠습니까?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. 오류 파일 : {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "지정한 파일에 선택한 타이틀의 DLC가 없습니다!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "개발자 전용으로 설계된 디버그 로깅을 활성화했습니다.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 디버그 로깅을 비활성화하는 것이 좋습니다. 지금 디버그 로깅을 비활성화하시겠습니까?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Y개발자만 사용하도록 설계된 셰이더 덤핑이 활성화되어 있습니다.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "최적의 성능을 위해 셰이더 덤핑을 비활성화하는 것이 좋습니다. 지금 셰이더 덤핑을 비활성화하시겠습니까?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "다른 게임이 이미 로드되었습니다",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "다른 게임을 시작하기 전에 에뮬레이션을 중지하거나 에뮬레이터를 닫으십시오.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "파일에 선택한 제목에 대한 업데이트가 포함되어 있지 않습니다!",
|
||||
"DialogSettingsBackendThreadingWarningTitle": "경고 - 백엔드 스레딩",
|
||||
"DialogSettingsBackendThreadingWarningMessage": "변경 사항을 완전히 적용하려면 이 옵션을 변경한 후 Ryujinx를 다시 시작해야 합니다. 플랫폼에 따라 Ryujinx를 사용할 때 드라이버 자체의 멀티스레딩을 수동으로 비활성화해야 할 수도 있습니다.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "특징",
|
||||
"SettingsTabGraphicsBackendMultithreading": "그래픽 백엔드 멀티스레딩 :",
|
||||
"CommonAuto": "자동적 인",
|
||||
"CommonOff": "끄다",
|
||||
"CommonOn": "켜짐",
|
||||
"InputDialogYes": "네",
|
||||
"InputDialogNo": "아니",
|
||||
"DialogProfileInvalidProfileNameErrorMessage": "파일 이름에 잘못된 기호가 있습니다. 다시 시도하십시오.",
|
||||
"MenuBarOptionsPauseEmulation": "정지시키다",
|
||||
"MenuBarOptionsResumeEmulation": "재개하다",
|
||||
"AboutUrlTooltipMessage": "기본 브라우저에서 Ryujinx 웹사이트를 열려면 클릭하십시오.",
|
||||
"AboutDisclaimerMessage": "Ryujinx는 Nintendo™와 제휴하지 않으며,\n어떤 식으로든 또는 그 파트너.",
|
||||
"AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com) 사용\nAmiibo 에뮬레이션에서.",
|
||||
"AboutPatreonUrlTooltipMessage": "기본 브라우저에서 Ryujinx Patreon 페이지를 열려면 클릭하세요.",
|
||||
"AboutGithubUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx GitHub 페이지를 엽니다.",
|
||||
"AboutDiscordUrlTooltipMessage": "기본 브라우저에서 Ryujinx Discord 서버 초대를 열려면 클릭하세요.",
|
||||
"AboutTwitterUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx Twitter 페이지를 엽니다.",
|
||||
"AboutRyujinxAboutTitle": "에 대한 :",
|
||||
"AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\nPatreon에서 지원해 주세요.\n모든 최신 뉴스는 Twitter 또는 Discord에서 확인하세요.\n기고에 관심이 있는 개발자는 GitHub 또는 Discord에서 자세한 내용을 확인할 수 있습니다.",
|
||||
"AboutRyujinxMaintainersTitle": "유지 관리 :",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "기본 브라우저에서 기여자 페이지를 열려면 클릭하십시오.",
|
||||
"AboutRyujinxSupprtersTitle": "Patreon에서 지원 :",
|
||||
"AmiiboSeriesLabel": "Amiibo 시리즈",
|
||||
"AmiiboCharacterLabel": "성격",
|
||||
"AmiiboScanButtonLabel": "스캔",
|
||||
"AmiiboOptionsShowAllLabel": "모든 Amiibo 표시",
|
||||
"AmiiboOptionsUsRandomTagLabel": "해킹: 임의의 태그 UUID 사용",
|
||||
"DlcManagerTableHeadingEnabledLabel": "활성화됨",
|
||||
"DlcManagerTableHeadingTitleIdLabel": "제목 ID",
|
||||
"DlcManagerTableHeadingContainerPathLabel": "컨테이너 경로",
|
||||
"DlcManagerTableHeadingFullPathLabel": "전체 경로",
|
||||
"DlcManagerRemoveAllButton": "모두 제거",
|
||||
"MenuBarOptionsChangeLanguage": "언어 변경",
|
||||
"CommonSort": "정렬",
|
||||
"CommonShowNames": "이름 표시",
|
||||
"CommonFavorite": "가장 좋아하는",
|
||||
"OrderAscending": "오름차순",
|
||||
"OrderDescending": "내림차순",
|
||||
"SettingsTabGraphicsFeatures": "특징ㆍ개선 사항",
|
||||
"ErrorWindowTitle": "오류 창",
|
||||
"ToggleDiscordTooltip": "Discord Rich Presence 활성화 또는 비활성화",
|
||||
"AddGameDirBoxTooltip": "게임 디렉토리를 입력하여 목록에 추가하세요",
|
||||
"AddGameDirTooltip": "목록에 게임 디렉토리 추가",
|
||||
"RemoveGameDirTooltip": "선택한 게임 디렉토리 제거",
|
||||
"CustomThemeCheckTooltip": "GUI에서 사용자 정의 테마 활성화 또는 비활성화",
|
||||
"CustomThemePathTooltip": "사용자 지정 GUI 테마 경로",
|
||||
"CustomThemeBrowseTooltip": "사용자 정의 GUI 테마 찾기",
|
||||
"DockModeToggleTooltip": "도킹 모드 활성화 또는 비활성화",
|
||||
"DirectKeyboardTooltip": "\"직접 키보드 액세스(HID) 지원\" 활성화 또는 비활성화(텍스트 입력 장치로 키보드에 대한 게임 액세스 제공)",
|
||||
"DirectMouseTooltip": "\"직접 마우스 액세스(HID) 지원\" 활성화 또는 비활성화(포인팅 장치로 마우스에 대한 게임 액세스 제공)",
|
||||
"RegionTooltip": "시스템 지역 변경",
|
||||
"LanguageTooltip": "시스템 언어 변경",
|
||||
"TimezoneTooltip": "시스템 시간대 변경",
|
||||
"TimeTooltip": "시스템 시간 변경",
|
||||
"VSyncToggleTooltip": "수직 동기화 활성화 또는 비활성화",
|
||||
"PptcToggleTooltip": "PPTC 활성화 또는 비활성화",
|
||||
"FsIntegrityToggleTooltip": "게임 콘텐츠 파일에 대한 무결성 검사 활성화",
|
||||
"AudioBackendTooltip": "오디오 백엔드 변경",
|
||||
"MemoryManagerTooltip": "게스트 메모리가 매핑되고 액세스되는 방식을 변경합니다. 에뮬레이트된 CPU 성능에 큰 영향을 줍니다.",
|
||||
"MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하십시오. 정확도는 가장 높지만 성능은 가장 느립니다.",
|
||||
"MemoryManagerHostTooltip": "호스트 주소 공간에서 메모리를 직접 매핑합니다. 훨씬 더 빠른 JIT 컴파일 및 실행.",
|
||||
"MemoryManagerUnsafeTooltip": "메모리를 직접 매핑하지만 액세스하기 전에 게스트 주소 공간 내의 주소를 마스킹하지 마십시오. 더 빠르지만 안전을 희생해야 합니다. 게스트 응용 프로그램은 Ryujinx의 어디에서나 메모리에 액세스할 수 있으므로 이 모드로 신뢰할 수 있는 프로그램만 실행하십시오.",
|
||||
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GiB에서 6GiB로 확장",
|
||||
"IgnoreMissingServicesTooltip": "누락된 서비스 무시 옵션 활성화 또는 비활성화",
|
||||
"GraphicsBackendThreadingTooltip": "그래픽 백엔드 멀티스레딩 활성화",
|
||||
"GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다. 셰이더 컴파일의 런타임 멀티스레딩을 허용하고, 말더듬을 줄이고, 자체 멀티스레딩 지원 없이 드라이버의 성능을 개선합니다. 멀티스레딩이 있는 드라이버에서 약간 다른 최대 성능. 드라이버 내장 멀티스레딩을 올바르게 비활성화하려면 Ryujinx를 다시 시작해야 할 수도 있고 최상의 성능을 얻으려면 수동으로 수행해야 할 수도 있습니다.",
|
||||
"ShaderCacheToggleTooltip": "셰이더 캐시 활성화 또는 비활성화",
|
||||
"ResolutionScaleTooltip": "적용 가능한 렌더 타겟에 적용된 해상도 배율",
|
||||
"ResolutionScaleEntryTooltip": "1.5와 같은 부동 소수점 해상도 스케일. 비적분 스케일은 문제나 충돌을 일으킬 가능성이 더 큽니다.",
|
||||
"AnisotropyTooltip": "이방성 필터링 수준(게임에서 요청한 값을 사용하려면 자동으로 설정)",
|
||||
"AspectRatioTooltip": "렌더러 창에 적용된 종횡비.",
|
||||
"ShaderDumpPathTooltip": "그래픽 셰이더 덤프 경로",
|
||||
"FileLogTooltip": "디스크의 파일에 대한 로깅 활성화 또는 비활성화",
|
||||
"StubLogTooltip": "스텁 로그 메시지 인쇄 활성화",
|
||||
"InfoLogTooltip": "정보 로그 메시지 인쇄 활성화",
|
||||
"WarnLogTooltip": "경고 로그 메시지 인쇄 활성화",
|
||||
"ErrorLogTooltip": "오류 로그 메시지 인쇄 활성화",
|
||||
"GuestLogTooltip": "게스트 로그 메시지 인쇄 활성화",
|
||||
"FileAccessLogTooltip": "파일 액세스 로그 메시지 인쇄 활성화",
|
||||
"FSAccessLogModeTooltip": "콘솔에 대한 FS 액세스 로그 출력을 활성화합니다. 가능한 모드는 0-3입니다",
|
||||
"DeveloperOptionTooltip": "주의해서 사용",
|
||||
"OpenGlLogLevel": "적절한 로그 수준이 활성화되어 있어야 합니다",
|
||||
"DebugLogTooltip": "디버그 로그 메시지 인쇄 활성화",
|
||||
"LoadApplicationFileTooltip": "로드할 Switch 호환 파일을 선택하려면 파일 선택기를 엽니다.",
|
||||
"LoadApplicationFolderTooltip": "파일 선택기를 열어 로드할 Switch 호환 가능하고 압축을 푼 응용 프로그램을 선택합니다",
|
||||
"OpenRyujinxFolderTooltip": "Ryujinx 파일 시스템 폴더 열기",
|
||||
"OpenRyujinxLogsTooltip": "로그가 기록되는 폴더를 엽니다.",
|
||||
"ExitTooltip": "Ryujinx 종료",
|
||||
"OpenSettingsTooltip": "설정 창 열기",
|
||||
"OpenProfileManagerTooltip": "사용자 프로필 관리자 창 열기",
|
||||
"StopEmulationTooltip": "현재 게임의 에뮬레이션을 중지하고 게임 선택으로 돌아가기",
|
||||
"CheckUpdatesTooltip": "Ryujinx 업데이트 확인",
|
||||
"OpenAboutTooltip": "정보 창 열기",
|
||||
"GridSize": "그리드 크기",
|
||||
"GridSizeTooltip": "그리드 항목의 크기 변경",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "포르투갈어(브라질)",
|
||||
"AboutRyujinxContributorsButtonHeader": "모든 기여자 보기",
|
||||
"SettingsTabSystemAudioVolume": "용량 : ",
|
||||
"AudioVolumeTooltip": "오디오 볼륨 변경",
|
||||
"SettingsTabSystemEnableInternetAccess": "게스트 인터넷 액세스 활성화s",
|
||||
"EnableInternetAccessTooltip": "게스트 인터넷 액세스를 활성화합니다. 활성화된 경우 응용 프로그램은 에뮬레이트된 스위치 콘솔이 인터넷에 연결된 것처럼 작동합니다. 경우에 따라 이 옵션이 비활성화된 경우에도 응용 프로그램이 인터넷에 계속 액세스할 수 있습니다",
|
||||
"GameListContextMenuManageCheatToolTip" : "치트 관리",
|
||||
"GameListContextMenuManageCheat" : "치트 관리",
|
||||
"ControllerSettingsStickRange" : "범위:",
|
||||
"DialogStopEmulationTitle" : "Ryujinx - 에뮬레이션 중지",
|
||||
"DialogStopEmulationMessage": "에뮬레이션을 중지하시겠습니까?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "오디오",
|
||||
"SettingsTabNetwork": "회로망",
|
||||
"SettingsTabNetworkConnection" : "네트워크 연결",
|
||||
"SettingsTabCpuCache" : "CPU 캐시",
|
||||
"SettingsTabCpuMemory" : "CPU 메모리",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
class LocaleManager : BaseModel
|
||||
{
|
||||
private const string DefaultLanguageCode = "en_US";
|
||||
|
||||
private Dictionary<string, string> _localeStrings;
|
||||
private ConcurrentDictionary<string, object[]> _dynamicValues;
|
||||
|
||||
public static LocaleManager Instance { get; } = new LocaleManager();
|
||||
public Dictionary<string, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
|
||||
|
||||
|
||||
public LocaleManager()
|
||||
{
|
||||
_localeStrings = new Dictionary<string, string>();
|
||||
_dynamicValues = new ConcurrentDictionary<string, object[]>();
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
string localeLanguageCode = CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value))
|
||||
{
|
||||
localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Load english first, if the target language translation is incomplete, we default to english.
|
||||
LoadDefaultLanguage();
|
||||
|
||||
if (localeLanguageCode != DefaultLanguageCode)
|
||||
{
|
||||
LoadLanguage(localeLanguageCode);
|
||||
}
|
||||
}
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_localeStrings.TryGetValue(key, out string value))
|
||||
{
|
||||
if (_dynamicValues.TryGetValue(key, out var dynamicValue))
|
||||
{
|
||||
return string.Format(value, dynamicValue);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
set
|
||||
{
|
||||
_localeStrings[key] = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDynamicValue(string key, params object[] values)
|
||||
{
|
||||
_dynamicValues[key] = values;
|
||||
|
||||
OnPropertyChanged("Item");
|
||||
}
|
||||
|
||||
public void LoadDefaultLanguage()
|
||||
{
|
||||
LoadLanguage(DefaultLanguageCode);
|
||||
}
|
||||
|
||||
public void LoadLanguage(string languageCode)
|
||||
{
|
||||
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
||||
|
||||
if (languageJson == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
this[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
ConfigurationState.Instance.Ui.LanguageCode.Value = languageCode;
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Helper
|
||||
{
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
static partial class MetalHelper
|
||||
{
|
||||
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||
|
||||
private struct Selector
|
||||
{
|
||||
public readonly IntPtr NativePtr;
|
||||
|
||||
public unsafe Selector(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
NativePtr = sel_registerName(data);
|
||||
}
|
||||
|
||||
public static implicit operator Selector(string value) => new Selector(value);
|
||||
}
|
||||
|
||||
private static unsafe IntPtr GetClass(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
return objc_getClass(data);
|
||||
}
|
||||
|
||||
private struct NSPoint
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
|
||||
public NSPoint(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
|
||||
private struct NSRect
|
||||
{
|
||||
public NSPoint Pos;
|
||||
public NSPoint Size;
|
||||
|
||||
public NSRect(double x, double y, double width, double height)
|
||||
{
|
||||
Pos = new NSPoint(x, y);
|
||||
Size = new NSPoint(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetMetalLayer(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
|
||||
{
|
||||
// Create a new CAMetalLayer.
|
||||
IntPtr layerClass = GetClass("CAMetalLayer");
|
||||
IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc");
|
||||
objc_msgSend(metalLayer, "init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
IntPtr nsViewClass = GetClass("NSView");
|
||||
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||
objc_msgSend(child, "init", new NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
objc_msgSend(child, "setWantsLayer:", (byte)1);
|
||||
objc_msgSend(child, "setLayer:", metalLayer);
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
updateBounds = (Rect rect) => {
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
nsView = child;
|
||||
return metalLayer;
|
||||
}
|
||||
|
||||
public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr sel_registerName(byte* data);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr objc_getClass(byte* data);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||
|
||||
[LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||
private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||
}
|
||||
}
|
@ -1,713 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using ICSharpCode.SharpZipLib.Tar;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Ryujinx.Ava;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Modules
|
||||
{
|
||||
internal static class Updater
|
||||
{
|
||||
private const string GitHubApiURL = "https://api.github.com";
|
||||
internal static bool Running;
|
||||
|
||||
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||
private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish");
|
||||
private static readonly int ConnectionCount = 4;
|
||||
|
||||
private static string _buildVer;
|
||||
private static string _platformExt;
|
||||
private static string _buildUrl;
|
||||
private static long _buildSize;
|
||||
|
||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
||||
|
||||
public static bool UpdateSuccessful { get; private set; }
|
||||
|
||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Running = true;
|
||||
mainWindow.CanUpdate = false;
|
||||
|
||||
// Detect current platform
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
_platformExt = "osx_x64.zip";
|
||||
}
|
||||
else if (OperatingSystem.IsWindows())
|
||||
{
|
||||
_platformExt = "win_x64.zip";
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
_platformExt = "linux_x64.tar.gz";
|
||||
}
|
||||
|
||||
Version newVersion;
|
||||
Version currentVersion;
|
||||
|
||||
try
|
||||
{
|
||||
currentVersion = Version.Parse(Program.Version);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get latest version number from GitHub API
|
||||
try
|
||||
{
|
||||
using (HttpClient jsonClient = ConstructHttpClient())
|
||||
{
|
||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest";
|
||||
|
||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
||||
JObject jsonRoot = JObject.Parse(fetchedJson);
|
||||
JToken assets = jsonRoot["assets"];
|
||||
|
||||
_buildVer = (string)jsonRoot["name"];
|
||||
|
||||
foreach (JToken asset in assets)
|
||||
{
|
||||
string assetName = (string)asset["name"];
|
||||
string assetState = (string)asset["state"];
|
||||
string downloadURL = (string)asset["browser_download_url"];
|
||||
|
||||
if (assetName.StartsWith("test-ava-ryujinx") && assetName.EndsWith(_platformExt))
|
||||
{
|
||||
_buildUrl = downloadURL;
|
||||
|
||||
if (assetState != "uploaded")
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If build not done, assume no new update are availaible.
|
||||
if (_buildUrl == null)
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, exception.Message);
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdaterFailedToGetVersionMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
newVersion = Version.Parse(_buildVer);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedGithubMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVersion <= currentVersion)
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
Running = false;
|
||||
mainWindow.CanUpdate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch build size information to learn chunk sizes.
|
||||
using (HttpClient buildSizeClient = ConstructHttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
||||
|
||||
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");
|
||||
|
||||
_buildSize = -1;
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
// Show a message asking the user if they want to update
|
||||
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["RyujinxUpdaterMessage"],
|
||||
$"{Program.Version} -> {newVersion}");
|
||||
|
||||
if (shouldUpdate)
|
||||
{
|
||||
UpdateRyujinx(mainWindow, _buildUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static HttpClient ConstructHttpClient()
|
||||
{
|
||||
HttpClient result = new HttpClient();
|
||||
|
||||
// Required by GitHub to interract with APIs.
|
||||
result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||
{
|
||||
UpdateSuccessful = false;
|
||||
|
||||
// Empty update dir, although it shouldn't ever have anything inside it
|
||||
if (Directory.Exists(UpdateDir))
|
||||
{
|
||||
Directory.Delete(UpdateDir, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(UpdateDir);
|
||||
|
||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
||||
|
||||
var taskDialog = new TaskDialog()
|
||||
{
|
||||
Header = LocaleManager.Instance["RyujinxUpdater"],
|
||||
SubHeader = LocaleManager.Instance["UpdaterDownloading"],
|
||||
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||
Buttons = { },
|
||||
ShowProgressBar = true
|
||||
};
|
||||
|
||||
taskDialog.XamlRoot = parent;
|
||||
|
||||
taskDialog.Opened += (s, e) =>
|
||||
{
|
||||
if (_buildSize >= 0)
|
||||
{
|
||||
DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
}
|
||||
};
|
||||
|
||||
await taskDialog.ShowAsync(true);
|
||||
|
||||
if (UpdateSuccessful)
|
||||
{
|
||||
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["DialogUpdaterCompleteMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterRestartMessage"]);
|
||||
|
||||
if (shouldRestart)
|
||||
{
|
||||
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||
|
||||
if (!Path.Exists(ryuExe))
|
||||
{
|
||||
ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx");
|
||||
}
|
||||
|
||||
SetFileExecutable(ryuExe);
|
||||
|
||||
Process.Start(ryuExe, CommandLineState.Arguments);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
// Multi-Threaded Updater
|
||||
long chunkSize = _buildSize / ConnectionCount;
|
||||
long remainderChunk = _buildSize % ConnectionCount;
|
||||
|
||||
int completedRequests = 0;
|
||||
int totalProgressPercentage = 0;
|
||||
int[] progressPercentage = new int[ConnectionCount];
|
||||
|
||||
List<byte[]> list = new List<byte[]>(ConnectionCount);
|
||||
List<WebClient> webClients = new List<WebClient>(ConnectionCount);
|
||||
|
||||
for (int i = 0; i < ConnectionCount; i++)
|
||||
{
|
||||
list.Add(Array.Empty<byte>());
|
||||
}
|
||||
|
||||
for (int i = 0; i < ConnectionCount; i++)
|
||||
{
|
||||
#pragma warning disable SYSLIB0014
|
||||
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
|
||||
using (WebClient client = new WebClient())
|
||||
#pragma warning restore SYSLIB0014
|
||||
{
|
||||
webClients.Add(client);
|
||||
|
||||
if (i == ConnectionCount - 1)
|
||||
{
|
||||
client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}");
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Headers.Add("Range", $"bytes={chunkSize * i}-{chunkSize * (i + 1) - 1}");
|
||||
}
|
||||
|
||||
client.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
int index = (int)args.UserState;
|
||||
|
||||
Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]);
|
||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||
|
||||
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
||||
};
|
||||
|
||||
client.DownloadDataCompleted += (_, args) =>
|
||||
{
|
||||
int index = (int)args.UserState;
|
||||
|
||||
if (args.Cancelled)
|
||||
{
|
||||
webClients[index].Dispose();
|
||||
|
||||
taskDialog.Hide();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
list[index] = args.Result;
|
||||
Interlocked.Increment(ref completedRequests);
|
||||
|
||||
if (Equals(completedRequests, ConnectionCount))
|
||||
{
|
||||
byte[] mergedFileBytes = new byte[_buildSize];
|
||||
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
||||
{
|
||||
Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length);
|
||||
destinationOffset += list[connectionIndex].Length;
|
||||
}
|
||||
|
||||
File.WriteAllBytes(updateFile, mergedFileBytes);
|
||||
|
||||
try
|
||||
{
|
||||
InstallUpdate(taskDialog, updateFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
client.DownloadDataAsync(new Uri(downloadUrl), i);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
for (int j = 0; j < webClients.Count; j++)
|
||||
{
|
||||
webClients[j].CancelAsync();
|
||||
}
|
||||
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
// We do not want to timeout while downloading
|
||||
client.Timeout = TimeSpan.FromDays(1);
|
||||
|
||||
using (HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||
using (Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result)
|
||||
{
|
||||
using (Stream updateFileStream = File.Open(updateFile, FileMode.Create))
|
||||
{
|
||||
long totalBytes = response.Content.Headers.ContentLength.Value;
|
||||
long byteWritten = 0;
|
||||
|
||||
byte[] buffer = new byte[32 * 1024];
|
||||
|
||||
while (true)
|
||||
{
|
||||
int readSize = remoteFileStream.Read(buffer);
|
||||
|
||||
if (readSize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
byteWritten += readSize;
|
||||
|
||||
taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal);
|
||||
|
||||
updateFileStream.Write(buffer, 0, readSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstallUpdate(taskDialog, updateFile);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double GetPercentage(double value, double max)
|
||||
{
|
||||
return max == 0 ? 0 : value / max * 100;
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile));
|
||||
worker.Name = "Updater.SingleThreadWorker";
|
||||
worker.Start();
|
||||
}
|
||||
|
||||
private static void SetFileExecutable(string path)
|
||||
{
|
||||
const UnixFileMode ExecutableFileMode = UnixFileMode.UserExecute |
|
||||
UnixFileMode.UserWrite |
|
||||
UnixFileMode.UserRead |
|
||||
UnixFileMode.GroupRead |
|
||||
UnixFileMode.GroupWrite |
|
||||
UnixFileMode.OtherRead |
|
||||
UnixFileMode.OtherWrite;
|
||||
|
||||
if (!OperatingSystem.IsWindows() && File.Exists(path))
|
||||
{
|
||||
File.SetUnixFileMode(path, ExecutableFileMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||
{
|
||||
// Extract Update
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
using (Stream inStream = File.OpenRead(updateFile))
|
||||
using (Stream gzipStream = new GZipInputStream(inStream))
|
||||
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
TarEntry tarEntry;
|
||||
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
||||
{
|
||||
if (tarEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, tarEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
{
|
||||
tarStream.CopyEntryContents(outStream);
|
||||
}
|
||||
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||
|
||||
TarEntry entry = tarEntry;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(entry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
taskDialog.SetProgressBarState(100, TaskDialogProgressState.Normal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Stream inStream = File.OpenRead(updateFile))
|
||||
using (ZipFile zipFile = new ZipFile(inStream))
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
double count = 0;
|
||||
foreach (ZipEntry zipEntry in zipFile)
|
||||
{
|
||||
count++;
|
||||
if (zipEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (Stream zipStream = zipFile.GetInputStream(zipEntry))
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
{
|
||||
zipStream.CopyTo(outStream);
|
||||
}
|
||||
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Delete downloaded zip
|
||||
File.Delete(updateFile);
|
||||
|
||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
// Replace old files
|
||||
await Task.Run(() =>
|
||||
{
|
||||
double count = 0;
|
||||
foreach (string file in allFiles)
|
||||
{
|
||||
count++;
|
||||
try
|
||||
{
|
||||
File.Move(file, file + ".ryuold");
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance["UpdaterRenameFailed"], file));
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
});
|
||||
|
||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
|
||||
});
|
||||
|
||||
Directory.Delete(UpdateDir, true);
|
||||
|
||||
SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"));
|
||||
|
||||
UpdateSuccessful = true;
|
||||
|
||||
taskDialog.Hide();
|
||||
}
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
public static bool CanUpdate(bool showWarnings, StyleableWindow parent)
|
||||
{
|
||||
#if !DISABLE_UPDATER
|
||||
if (RuntimeInformation.OSArchitecture != Architecture.X64)
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterArchNotSupportedMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterArchNotSupportedSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterNoInternetMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterNoInternetSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid())
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterDirtyBuildMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (showWarnings)
|
||||
{
|
||||
if (ReleaseInformations.IsFlatHubBuild())
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterFlatpakNotSupportedMessage"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
// NOTE: This method should always reflect the latest build layout.s
|
||||
private static IEnumerable<string> EnumerateFilesToDelete()
|
||||
{
|
||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
foreach (string dir in WindowsDependencyDirs)
|
||||
{
|
||||
string dirPath = Path.Combine(HomeDir, dir);
|
||||
if (Directory.Exists(dirPath))
|
||||
{
|
||||
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog)
|
||||
{
|
||||
var total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length;
|
||||
foreach (string directory in Directory.GetDirectories(root))
|
||||
{
|
||||
string dirName = Path.GetFileName(directory);
|
||||
|
||||
if (!Directory.Exists(Path.Combine(dest, dirName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
||||
}
|
||||
|
||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog);
|
||||
}
|
||||
|
||||
double count = 0;
|
||||
foreach (string file in Directory.GetFiles(root))
|
||||
{
|
||||
count++;
|
||||
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanupUpdate()
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(HomeDir, "*.ryuold", SearchOption.AllDirectories))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using SPB.Graphics;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
internal class AvaloniaGlxContext : SPB.Platform.GLX.GLXOpenGLContext
|
||||
{
|
||||
public AvaloniaGlxContext(IntPtr handle)
|
||||
: base(FramebufferFormat.Default, 0, 0, 0, false, null)
|
||||
{
|
||||
ContextHandle = handle;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using SPB.Graphics;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
internal class AvaloniaWglContext : SPB.Platform.WGL.WGLOpenGLContext
|
||||
{
|
||||
public AvaloniaWglContext(IntPtr handle)
|
||||
: base(FramebufferFormat.Default, 0, 0, 0, false, null)
|
||||
{
|
||||
ContextHandle = handle;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
using Ryujinx.Ava.Ui.Helper;
|
||||
using SPB.Graphics;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.GLX;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public class EmbeddedWindow : NativeControlHost
|
||||
{
|
||||
private WindowProc _wndProcDelegate;
|
||||
private string _className;
|
||||
|
||||
protected GLXWindow X11Window { get; set; }
|
||||
protected IntPtr WindowHandle { get; set; }
|
||||
protected IntPtr X11Display { get; set; }
|
||||
protected IntPtr NsView { get; set; }
|
||||
protected IntPtr MetalLayer { get; set; }
|
||||
|
||||
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||
|
||||
public event EventHandler<IntPtr> WindowCreated;
|
||||
public event EventHandler<Size> SizeChanged;
|
||||
|
||||
protected virtual void OnWindowDestroyed() { }
|
||||
protected virtual void OnWindowDestroying()
|
||||
{
|
||||
WindowHandle = IntPtr.Zero;
|
||||
X11Display = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public EmbeddedWindow()
|
||||
{
|
||||
var stateObserverable = this.GetObservable(BoundsProperty);
|
||||
|
||||
stateObserverable.Subscribe(StateChanged);
|
||||
|
||||
this.Initialized += NativeEmbeddedWindow_Initialized;
|
||||
}
|
||||
|
||||
public virtual void OnWindowCreated() { }
|
||||
|
||||
private void NativeEmbeddedWindow_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
OnWindowCreated();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
WindowCreated?.Invoke(this, WindowHandle);
|
||||
});
|
||||
}
|
||||
|
||||
private void StateChanged(Rect rect)
|
||||
{
|
||||
SizeChanged?.Invoke(this, rect.Size);
|
||||
_updateBoundsCallback?.Invoke(rect);
|
||||
}
|
||||
|
||||
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
return CreateLinux(parent);
|
||||
}
|
||||
else if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return CreateWin32(parent);
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
return CreateMacOs(parent);
|
||||
}
|
||||
|
||||
return base.CreateNativeControlCore(parent);
|
||||
}
|
||||
|
||||
protected override void DestroyNativeControlCore(IPlatformHandle control)
|
||||
{
|
||||
OnWindowDestroying();
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
DestroyLinux();
|
||||
}
|
||||
else if (OperatingSystem.IsWindows())
|
||||
{
|
||||
DestroyWin32(control);
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
DestroyMacOS();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DestroyNativeControlCore(control);
|
||||
}
|
||||
|
||||
OnWindowDestroyed();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
protected virtual IPlatformHandle CreateLinux(IPlatformHandle parent)
|
||||
{
|
||||
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
|
||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||
|
||||
return new PlatformHandle(WindowHandle, "X11");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
IPlatformHandle CreateWin32(IPlatformHandle parent)
|
||||
{
|
||||
_className = "NativeWindow-" + Guid.NewGuid();
|
||||
_wndProcDelegate = WndProc;
|
||||
var wndClassEx = new WNDCLASSEX
|
||||
{
|
||||
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
|
||||
hInstance = GetModuleHandle(null),
|
||||
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
|
||||
style = ClassStyles.CS_OWNDC,
|
||||
lpszClassName = Marshal.StringToHGlobalUni(_className),
|
||||
hCursor = LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW)
|
||||
};
|
||||
|
||||
var atom = RegisterClassEx(ref wndClassEx);
|
||||
|
||||
var handle = CreateWindowEx(
|
||||
0,
|
||||
_className,
|
||||
"NativeWindow",
|
||||
WindowStyles.WS_CHILD,
|
||||
0,
|
||||
0,
|
||||
640,
|
||||
480,
|
||||
parent.Handle,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero);
|
||||
|
||||
WindowHandle = handle;
|
||||
|
||||
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
|
||||
|
||||
return new PlatformHandle(WindowHandle, "HWND");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
|
||||
var root = VisualRoot as Window;
|
||||
bool isLeft = false;
|
||||
switch (msg)
|
||||
{
|
||||
case WindowsMessages.LBUTTONDOWN:
|
||||
case WindowsMessages.RBUTTONDOWN:
|
||||
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
||||
this.RaiseEvent(new PointerPressedEventArgs(
|
||||
this,
|
||||
new Pointer(0, PointerType.Mouse, true),
|
||||
root,
|
||||
this.TranslatePoint(point, root).Value,
|
||||
(ulong)Environment.TickCount64,
|
||||
new PointerPointProperties(isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed),
|
||||
KeyModifiers.None));
|
||||
break;
|
||||
case WindowsMessages.LBUTTONUP:
|
||||
case WindowsMessages.RBUTTONUP:
|
||||
isLeft = msg == WindowsMessages.LBUTTONUP;
|
||||
this.RaiseEvent(new PointerReleasedEventArgs(
|
||||
this,
|
||||
new Pointer(0, PointerType.Mouse, true),
|
||||
root,
|
||||
this.TranslatePoint(point, root).Value,
|
||||
(ulong)Environment.TickCount64,
|
||||
new PointerPointProperties(isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased),
|
||||
KeyModifiers.None,
|
||||
isLeft ? MouseButton.Left : MouseButton.Right));
|
||||
break;
|
||||
case WindowsMessages.MOUSEMOVE:
|
||||
this.RaiseEvent(new PointerEventArgs(
|
||||
PointerMovedEvent,
|
||||
this,
|
||||
new Pointer(0, PointerType.Mouse, true),
|
||||
root,
|
||||
this.TranslatePoint(point, root).Value,
|
||||
(ulong)Environment.TickCount64,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
||||
KeyModifiers.None));
|
||||
break;
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
IPlatformHandle CreateMacOs(IPlatformHandle parent)
|
||||
{
|
||||
MetalLayer = MetalHelper.GetMetalLayer(out IntPtr nsView, out _updateBoundsCallback);
|
||||
|
||||
NsView = nsView;
|
||||
|
||||
return new PlatformHandle(nsView, "NSView");
|
||||
}
|
||||
|
||||
void DestroyLinux()
|
||||
{
|
||||
X11Window?.Dispose();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
void DestroyWin32(IPlatformHandle handle)
|
||||
{
|
||||
DestroyWindow(handle.Handle);
|
||||
UnregisterClass(_className, GetModuleHandle(null));
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
void DestroyMacOS()
|
||||
{
|
||||
MetalHelper.DestroyMetalLayer(NsView, MetalLayer);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.GameGridView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFavorite}"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenTitleUpdateManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDownloadableContentManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageDlc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenCheatManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenSdModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
|
||||
<MenuItem
|
||||
Command="{Binding PurgePtcCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding PurgeShaderCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenPtcDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenShaderCacheDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
|
||||
<MenuItem
|
||||
Command="{Binding ExtractExeFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractRomFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractLogo}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataLogo}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Grid.Row="0"
|
||||
Padding="8"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ContextFlyout="{StaticResource GameContextMenu}"
|
||||
DoubleTapped="GameList_DoubleTapped"
|
||||
Items="{Binding AppsObservableList}"
|
||||
SelectionChanged="GameList_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<flex:FlexPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AlignContent="FlexStart"
|
||||
JustifyContent="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="5" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.7">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="MaxWidth" Value="0" />
|
||||
<Setter Property="Opacity" Value="0.0" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="MaxWidth" Value="1000" />
|
||||
<Setter Property="Opacity" Value="0.3" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="MaxWidth" Value="1000" />
|
||||
<Setter Property="Opacity" Value="1.0" />
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="4">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<Panel
|
||||
Grid.Row="1"
|
||||
Height="50"
|
||||
Margin="0 10 0 0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</Panel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ui:SymbolIcon
|
||||
Margin="5,5,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="16"
|
||||
Foreground="{DynamicResource SystemAccentColor}"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="StarFilled" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,82 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using LibHac.Common;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class GameGridView : UserControl
|
||||
{
|
||||
private ApplicationData _selectedApplication;
|
||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
}
|
||||
|
||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
var selected = listBox.SelectedItem as ApplicationData;
|
||||
|
||||
_selectedApplication = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData SelectedApplication => _selectedApplication;
|
||||
|
||||
public GameGridView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
}
|
||||
|
||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
if (selection != null)
|
||||
{
|
||||
if (sender is ContextMenu menu)
|
||||
{
|
||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
|
||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.GameListView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFavorite}"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenTitleUpdateManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDownloadableContentManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageDlc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenCheatManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenSdModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
|
||||
<MenuItem
|
||||
Command="{Binding PurgePtcCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding PurgeShaderCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenPtcDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenShaderCacheDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
|
||||
<MenuItem
|
||||
Command="{Binding ExtractExeFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractRomFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractLogo}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataLogo}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Name="GameListBox"
|
||||
Grid.Row="0"
|
||||
Padding="8"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ContextFlyout="{StaticResource GameContextMenu}"
|
||||
DoubleTapped="GameList_DoubleTapped"
|
||||
Items="{Binding AppsObservableList}"
|
||||
SelectionChanged="GameList_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="2" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
<Setter Property="BorderThickness" Value="2"/>
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.7">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="MaxHeight" Value="0" />
|
||||
<Setter Property="Opacity" Value="0.0" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="MaxHeight" Value="1000" />
|
||||
<Setter Property="Opacity" Value="0.3" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="MaxHeight" Value="1000" />
|
||||
<Setter Property="Opacity" Value="1.0" />
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||
<Setter Property="MinHeight" Value="100" />
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="0"
|
||||
Padding="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="0"
|
||||
Margin="0"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Vertical"
|
||||
Spacing="5" >
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Developer}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Version}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="3"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Vertical"
|
||||
Spacing="5">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TimePlayed}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding LastPlayed}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding FileSize}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<ui:SymbolIcon
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="-5,-5,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="16"
|
||||
Foreground="{DynamicResource SystemAccentColor}"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="StarFilled" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,82 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using LibHac.Common;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class GameListView : UserControl
|
||||
{
|
||||
private ApplicationData _selectedApplication;
|
||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
}
|
||||
|
||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
var selected = listBox.SelectedItem as ApplicationData;
|
||||
|
||||
_selectedApplication = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData SelectedApplication => _selectedApplication;
|
||||
|
||||
public GameListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
}
|
||||
|
||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
if (selection != null)
|
||||
{
|
||||
if (sender is ContextMenu menu)
|
||||
{
|
||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
|
||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public enum Glyph : int
|
||||
{
|
||||
List,
|
||||
Grid,
|
||||
Chip
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using Avalonia.OpenGL;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
internal static class IGlContextExtension
|
||||
{
|
||||
public static OpenGLContextBase AsOpenGLContextBase(this IGlContext context)
|
||||
{
|
||||
var handle = (IntPtr)context.GetType().GetProperty("Handle").GetValue(context);
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return new AvaloniaWglContext(handle);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
return new AvaloniaGlxContext(handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.InputDialog"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid
|
||||
Margin="5,10,5,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock HorizontalAlignment="Center" Text="{Binding Message}" />
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center"
|
||||
MaxLength="{Binding MaxLength}"
|
||||
Text="{Binding Input, Mode=TwoWay}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="5,5,5,10"
|
||||
HorizontalAlignment="Center"
|
||||
Text="{Binding SubMessage}" />
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,56 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class InputDialog : UserControl
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public string Input { get; set; }
|
||||
public string SubMessage { get; set; }
|
||||
|
||||
public uint MaxLength { get; }
|
||||
|
||||
public InputDialog(string message, string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
Message = message;
|
||||
Input = input;
|
||||
SubMessage = subMessage;
|
||||
MaxLength = maxLength;
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
public InputDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, string message,
|
||||
string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
UserResult result = UserResult.Cancel;
|
||||
|
||||
InputDialog content = new InputDialog(message, input, subMessage, maxLength);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = title,
|
||||
PrimaryButtonText = LocaleManager.Instance["InputDialogOk"],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["InputDialogCancel"],
|
||||
Content = content,
|
||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = UserResult.Ok;
|
||||
input = content.Input;
|
||||
})
|
||||
};
|
||||
await contentDialog.ShowAsync();
|
||||
|
||||
return (result, input);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost"
|
||||
Focusable="True">
|
||||
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
x:Name="ContentFrame" />
|
||||
</UserControl>
|
@ -1,91 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using LibHac;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class NavigationDialogHost : UserControl
|
||||
{
|
||||
public AccountManager AccountManager { get; }
|
||||
public ContentManager ContentManager { get; }
|
||||
public VirtualFileSystem VirtualFileSystem { get; }
|
||||
public HorizonClient HorizonClient { get; }
|
||||
public UserProfileViewModel ViewModel { get; set; }
|
||||
|
||||
public NavigationDialogHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
||||
VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
|
||||
{
|
||||
AccountManager = accountManager;
|
||||
ContentManager = contentManager;
|
||||
VirtualFileSystem = virtualFileSystem;
|
||||
HorizonClient = horizonClient;
|
||||
ViewModel = new UserProfileViewModel(this);
|
||||
|
||||
|
||||
if (contentManager.GetCurrentFirmwareVersion() != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
AvatarProfileViewModel.PreloadAvatars(contentManager, virtualFileSystem);
|
||||
});
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void GoBack(object parameter = null)
|
||||
{
|
||||
if (ContentFrame.BackStack.Count > 0)
|
||||
{
|
||||
ContentFrame.GoBack();
|
||||
}
|
||||
|
||||
ViewModel.LoadProfiles();
|
||||
}
|
||||
|
||||
public void Navigate(Type sourcePageType, object parameter)
|
||||
{
|
||||
ContentFrame.Navigate(sourcePageType, parameter);
|
||||
}
|
||||
|
||||
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
|
||||
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
|
||||
{
|
||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
||||
PrimaryButtonText = "",
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||
Content = content,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
||||
contentDialog.Closed += (sender, args) =>
|
||||
{
|
||||
content.ViewModel.Dispose();
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
||||
Navigate(typeof(UserSelector), this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog"
|
||||
Focusable="True">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="70" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock FontWeight="Bold" FontSize="18" HorizontalAlignment="Center" Grid.Row="1"
|
||||
Text="{Locale:Locale ProfileImageSelectionHeader}" />
|
||||
<TextBlock FontWeight="Bold" Grid.Row="2" Margin="10" MaxWidth="400" TextWrapping="Wrap"
|
||||
HorizontalAlignment="Center" TextAlignment="Center" Text="{Locale:Locale ProfileImageSelectionNote}" />
|
||||
<StackPanel Margin="5,0" Spacing="10" Grid.Row="4" HorizontalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button Name="Import" Click="Import_OnClick" Width="200">
|
||||
<TextBlock Text="{Locale:Locale ProfileImageSelectionImportImage}" />
|
||||
</Button>
|
||||
<Button Name="SelectFirmwareImage" IsEnabled="{Binding FirmwareFound}" Click="SelectFirmwareImage_OnClick"
|
||||
Width="200">
|
||||
<TextBlock Text="{Locale:Locale ProfileImageSelectionSelectAvatar}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,8 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost"
|
||||
Focusable="True">
|
||||
</UserControl>
|
@ -1,126 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Silk.NET.Vulkan;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class RendererHost : UserControl, IDisposable
|
||||
{
|
||||
private readonly GraphicsDebugLevel _graphicsDebugLevel;
|
||||
private EmbeddedWindow _currentWindow;
|
||||
|
||||
public bool IsVulkan { get; private set; }
|
||||
|
||||
public RendererHost(GraphicsDebugLevel graphicsDebugLevel)
|
||||
{
|
||||
_graphicsDebugLevel = graphicsDebugLevel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public RendererHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void CreateOpenGL()
|
||||
{
|
||||
Dispose();
|
||||
|
||||
_currentWindow = new OpenGLEmbeddedWindow(3, 3, _graphicsDebugLevel);
|
||||
Initialize();
|
||||
|
||||
IsVulkan = false;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
||||
Content = _currentWindow;
|
||||
}
|
||||
|
||||
public void CreateVulkan()
|
||||
{
|
||||
Dispose();
|
||||
|
||||
_currentWindow = new VulkanEmbeddedWindow();
|
||||
Initialize();
|
||||
|
||||
IsVulkan = true;
|
||||
}
|
||||
|
||||
public OpenGLContextBase GetContext()
|
||||
{
|
||||
if (_currentWindow is OpenGLEmbeddedWindow openGlEmbeddedWindow)
|
||||
{
|
||||
return openGlEmbeddedWindow.Context;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void CurrentWindow_SizeChanged(object sender, Size e)
|
||||
{
|
||||
SizeChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void CurrentWindow_WindowCreated(object sender, IntPtr e)
|
||||
{
|
||||
RendererInitialized?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
if (_currentWindow is OpenGLEmbeddedWindow openGlEmbeddedWindow)
|
||||
{
|
||||
openGlEmbeddedWindow.MakeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeCurrent(SwappableNativeWindowBase window)
|
||||
{
|
||||
if (_currentWindow is OpenGLEmbeddedWindow openGlEmbeddedWindow)
|
||||
{
|
||||
openGlEmbeddedWindow.MakeCurrent(window);
|
||||
}
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
{
|
||||
if (_currentWindow is OpenGLEmbeddedWindow openGlEmbeddedWindow)
|
||||
{
|
||||
openGlEmbeddedWindow.SwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> RendererInitialized;
|
||||
public event Action<object, Size> SizeChanged;
|
||||
public void Dispose()
|
||||
{
|
||||
if (_currentWindow != null)
|
||||
{
|
||||
_currentWindow.WindowCreated -= CurrentWindow_WindowCreated;
|
||||
_currentWindow.SizeChanged -= CurrentWindow_SizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public SurfaceKHR CreateVulkanSurface(Instance instance, Vk api)
|
||||
{
|
||||
return (_currentWindow is VulkanEmbeddedWindow vulkanEmbeddedWindow)
|
||||
? vulkanEmbeddedWindow.CreateSurface(instance)
|
||||
: default;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
Height="400"
|
||||
Width="550"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" />
|
||||
<ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
|
||||
<ComboBoxItem>
|
||||
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||
Content="{locale:Locale Name}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||
Content="{locale:Locale Size}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
|
||||
<ComboBoxItem>
|
||||
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||
Content="{locale:Locale OrderAscending}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
|
||||
Content="{locale:Locale Descending}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<Grid Grid.Column="1" HorizontalAlignment="Stretch" Margin="10,0, 0, 0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="{locale:Locale Search}" VerticalAlignment="Center"/>
|
||||
<TextBox Margin="5,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Search}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Border Grid.Row="1" Margin="0,5" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ListBox Name="SaveList" Items="{Binding View}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:SaveModel">
|
||||
<Grid HorizontalAlignment="Stretch" Margin="0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<Border Height="42" Margin="2" Width="42" Padding="10"
|
||||
IsVisible="{Binding !InGameList}">
|
||||
<ui:SymbolIcon Symbol="Help" FontSize="30" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<Image IsVisible="{Binding InGameList}"
|
||||
Margin="2"
|
||||
Width="42"
|
||||
Height="42"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<TextBlock MaxLines="3" Width="320" Margin="5" TextWrapping="Wrap"
|
||||
Text="{Binding Title}" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Spacing="10" HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Label Content="{Binding SizeString}" IsVisible="{Binding SizeAvailable}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||
MinWidth="0" MinHeight="0" Name="OpenLocation" Command="{Binding OpenLocation}">
|
||||
<ui:SymbolIcon Symbol="OpenFolder" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Button>
|
||||
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
|
||||
MinWidth="0" MinHeight="0" Name="Delete" Command="{Binding Delete}">
|
||||
<ui:SymbolIcon Symbol="Delete" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,160 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using LibHac;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using Ryujinx.Ava.Common;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class SaveManager : UserControl
|
||||
{
|
||||
private readonly UserProfile _userProfile;
|
||||
private readonly HorizonClient _horizonClient;
|
||||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
private int _sortIndex;
|
||||
private int _orderIndex;
|
||||
private ObservableCollection<SaveModel> _view = new ObservableCollection<SaveModel>();
|
||||
private string _search;
|
||||
|
||||
public ObservableCollection<SaveModel> Saves { get; set; } = new ObservableCollection<SaveModel>();
|
||||
|
||||
public ObservableCollection<SaveModel> View
|
||||
{
|
||||
get => _view;
|
||||
set => _view = value;
|
||||
}
|
||||
|
||||
public int SortIndex
|
||||
{
|
||||
get => _sortIndex;
|
||||
set
|
||||
{
|
||||
_sortIndex = value;
|
||||
Sort();
|
||||
}
|
||||
}
|
||||
|
||||
public int OrderIndex
|
||||
{
|
||||
get => _orderIndex;
|
||||
set
|
||||
{
|
||||
_orderIndex = value;
|
||||
Sort();
|
||||
}
|
||||
}
|
||||
|
||||
public string Search
|
||||
{
|
||||
get => _search;
|
||||
set
|
||||
{
|
||||
_search = value;
|
||||
Sort();
|
||||
}
|
||||
}
|
||||
|
||||
public SaveManager()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public SaveManager(UserProfile userProfile, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
|
||||
{
|
||||
_userProfile = userProfile;
|
||||
_horizonClient = horizonClient;
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
InitializeComponent();
|
||||
|
||||
DataContext = this;
|
||||
|
||||
Task.Run(LoadSaves);
|
||||
}
|
||||
|
||||
public void LoadSaves()
|
||||
{
|
||||
Saves.Clear();
|
||||
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
|
||||
new UserId((ulong)_userProfile.UserId.High, (ulong)_userProfile.UserId.Low), saveDataId: default, index: default);
|
||||
|
||||
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||
|
||||
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
||||
|
||||
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||
|
||||
while (true)
|
||||
{
|
||||
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
||||
|
||||
if (readCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < readCount; i++)
|
||||
{
|
||||
var save = saveDataInfo[i];
|
||||
if (save.ProgramId.Value != 0)
|
||||
{
|
||||
var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
|
||||
Saves.Add(saveModel);
|
||||
saveModel.DeleteAction = () => { Saves.Remove(saveModel); };
|
||||
}
|
||||
|
||||
Sort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Sort()
|
||||
{
|
||||
Saves.AsObservableChangeSet()
|
||||
.Filter(Filter)
|
||||
.Sort(GetComparer())
|
||||
.Bind(out var view).AsObservableList();
|
||||
|
||||
_view.Clear();
|
||||
_view.AddRange(view);
|
||||
}
|
||||
|
||||
private IComparer<SaveModel> GetComparer()
|
||||
{
|
||||
switch (SortIndex)
|
||||
{
|
||||
case 0:
|
||||
return OrderIndex == 0
|
||||
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
|
||||
: SortExpressionComparer<SaveModel>.Descending(save => save.Title);
|
||||
case 1:
|
||||
return OrderIndex == 0
|
||||
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
|
||||
: SortExpressionComparer<SaveModel>.Descending(save => save.Size);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool Filter(object arg)
|
||||
{
|
||||
if (arg is SaveModel save)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UpdateWaitWindow : StyleableWindow
|
||||
{
|
||||
public UpdateWaitWindow(string primaryText, string secondaryText) : this()
|
||||
{
|
||||
PrimaryText.Text = primaryText;
|
||||
SecondaryText.Text = secondaryText;
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
}
|
||||
|
||||
public UpdateWaitWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.UserEditor"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
Margin="0"
|
||||
MinWidth="500"
|
||||
Padding="0"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<Image
|
||||
Name="ProfileImage"
|
||||
Width="96"
|
||||
Height="96"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
||||
<Button
|
||||
Name="ChangePictureButton"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="ChangePictureButton_Click"
|
||||
Content="{Locale:Locale UserProfilesChangeProfileImage}" />
|
||||
<Button
|
||||
Name="AddPictureButton"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="ChangePictureButton_Click"
|
||||
Content="{Locale:Locale UserProfilesSetProfileImage}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="5,10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Text="{Locale:Locale UserProfilesName}" />
|
||||
<TextBox
|
||||
Name="NameBox"
|
||||
Width="300"
|
||||
HorizontalAlignment="Stretch"
|
||||
MaxLength="{Binding MaxProfileNameLength}"
|
||||
Text="{Binding Name}" />
|
||||
<TextBlock Name="IdText" Text="{Locale:Locale UserProfilesUserId}" />
|
||||
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<Button
|
||||
Name="SaveButton"
|
||||
Click="SaveButton_Click"
|
||||
Content="{Locale:Locale Save}" />
|
||||
<Button
|
||||
Name="CloseButton"
|
||||
HorizontalAlignment="Right"
|
||||
Click="CloseButton_Click"
|
||||
Content="{Locale:Locale Discard}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,117 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Navigation;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UserEditor : UserControl
|
||||
{
|
||||
private NavigationDialogHost _parent;
|
||||
private UserProfile _profile;
|
||||
private bool _isNewUser;
|
||||
|
||||
public TempProfile TempProfile { get; set; }
|
||||
public uint MaxProfileNameLength => 0x20;
|
||||
|
||||
public UserEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||
{
|
||||
NavigatedTo(e);
|
||||
}, RoutingStrategies.Direct);
|
||||
}
|
||||
|
||||
private void NavigatedTo(NavigationEventArgs arg)
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
switch (arg.NavigationMode)
|
||||
{
|
||||
case NavigationMode.New:
|
||||
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
||||
_isNewUser = args.isNewUser;
|
||||
_profile = args.profile;
|
||||
TempProfile = new TempProfile(_profile);
|
||||
|
||||
_parent = args.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
DataContext = TempProfile;
|
||||
|
||||
AddPictureButton.IsVisible = _isNewUser;
|
||||
IdLabel.IsVisible = _profile != null;
|
||||
IdText.IsVisible = _profile != null;
|
||||
ChangePictureButton.IsVisible = !_isNewUser;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_parent?.GoBack();
|
||||
}
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataValidationErrors.ClearErrors(NameBox);
|
||||
bool isInvalid = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TempProfile.Name))
|
||||
{
|
||||
DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance["UserProfileEmptyNameError"]));
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (TempProfile.Image == null)
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UserProfileNoImageError"], "");
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_profile != null && !_isNewUser)
|
||||
{
|
||||
_profile.Name = TempProfile.Name;
|
||||
_profile.Image = TempProfile.Image;
|
||||
_profile.UpdateState();
|
||||
_parent.AccountManager.SetUserName(_profile.UserId, _profile.Name);
|
||||
_parent.AccountManager.SetUserImage(_profile.UserId, _profile.Image);
|
||||
}
|
||||
else if (_isNewUser)
|
||||
{
|
||||
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image, TempProfile.UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent?.GoBack();
|
||||
}
|
||||
|
||||
public void SelectProfileImage()
|
||||
{
|
||||
_parent.Navigate(typeof(ProfileImageSelectionDialog), (_parent, TempProfile));
|
||||
}
|
||||
|
||||
private void ChangePictureButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_profile != null || _isNewUser)
|
||||
{
|
||||
SelectProfileImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
MinWidth="500"
|
||||
MinHeight="400"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer"
|
||||
Focusable="True">
|
||||
<Design.DataContext>
|
||||
<viewModels:UserProfileViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Button Grid.Row="0"
|
||||
Margin="5"
|
||||
Height="30"
|
||||
Width="50"
|
||||
MinWidth="50"
|
||||
HorizontalAlignment="Left"
|
||||
Command="{Binding GoBack}">
|
||||
<ui:SymbolIcon Symbol="Back"/>
|
||||
</Button>
|
||||
<TextBlock Grid.Row="1"
|
||||
Text="{Locale:Locale UserProfilesRecoverHeading}"/>
|
||||
<ListBox
|
||||
Margin="5"
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Items="{Binding LostProfiles}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Margin="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid Margin="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding UserId}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<Button Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding Recover}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="{Locale:Locale Recover}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,44 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Navigation;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UserRecoverer : UserControl
|
||||
{
|
||||
private UserProfileViewModel _viewModel;
|
||||
private NavigationDialogHost _parent;
|
||||
|
||||
public UserRecoverer()
|
||||
{
|
||||
InitializeComponent();
|
||||
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||
{
|
||||
NavigatedTo(e);
|
||||
}, RoutingStrategies.Direct);
|
||||
}
|
||||
|
||||
private void NavigatedTo(NavigationEventArgs arg)
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
switch (arg.NavigationMode)
|
||||
{
|
||||
case NavigationMode.New:
|
||||
var args = ((NavigationDialogHost parent, UserProfileViewModel viewModel))arg.Parameter;
|
||||
|
||||
_viewModel = args.viewModel;
|
||||
_parent = args.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
DataContext = _viewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.UserSelector"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
d:DesignHeight="450"
|
||||
MinWidth="500"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Design.DataContext>
|
||||
<viewModels:UserProfileViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Margin="5"
|
||||
MaxHeight="300"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
DoubleTapped="ProfilesList_DoubleTapped"
|
||||
Items="{Binding Profiles}"
|
||||
SelectionChanged="SelectingItemsControl_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<flex:FlexPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AlignContent="FlexStart"
|
||||
JustifyContent="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Width="96"
|
||||
Height="96"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Height="30"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Name}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Width="10"
|
||||
Height="10"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Background="LimeGreen"
|
||||
CornerRadius="5"
|
||||
IsVisible="{Binding IsOpened}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="2"
|
||||
Command="{Binding AddUser}"
|
||||
Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Grid.Row="0"
|
||||
Margin="2"
|
||||
Grid.Column="1"
|
||||
Command="{Binding EditUser}"
|
||||
Content="{Locale:Locale UserProfilesEditProfile}"
|
||||
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="2"
|
||||
Content="{Locale:Locale UserProfilesManageSaves}"
|
||||
Command="{Binding ManageSaves}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="2"
|
||||
Command="{Binding DeleteUser}"
|
||||
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
||||
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Column="0"
|
||||
Margin="2"
|
||||
Command="{Binding RecoverLostAccounts}"
|
||||
Content="{Locale:Locale UserProfilesRecoverLostAccounts}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,77 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Navigation;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UserSelector : UserControl
|
||||
{
|
||||
private NavigationDialogHost _parent;
|
||||
public UserProfileViewModel ViewModel { get; set; }
|
||||
|
||||
public UserSelector()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||
{
|
||||
NavigatedTo(e);
|
||||
}, RoutingStrategies.Direct);
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigatedTo(NavigationEventArgs arg)
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
if (arg.NavigationMode == NavigationMode.New)
|
||||
{
|
||||
_parent = (NavigationDialogHost)arg.Parameter;
|
||||
ViewModel = _parent.ViewModel;
|
||||
}
|
||||
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfilesList_DoubleTapped(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
int selectedIndex = listBox.SelectedIndex;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
||||
{
|
||||
ViewModel.SelectedProfile = ViewModel.Profiles[selectedIndex];
|
||||
|
||||
_parent?.AccountManager?.OpenUser(ViewModel.SelectedProfile.UserId);
|
||||
|
||||
ViewModel.LoadProfiles();
|
||||
|
||||
foreach (UserProfile profile in ViewModel.Profiles)
|
||||
{
|
||||
profile.UpdateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectingItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
int selectedIndex = listBox.SelectedIndex;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
||||
{
|
||||
ViewModel.HighlightedProfile = ViewModel.Profiles[selectedIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using Avalonia.Platform;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Silk.NET.Vulkan;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using SPB.Platform.GLX;
|
||||
using SPB.Platform.Metal;
|
||||
using SPB.Platform.Win32;
|
||||
using SPB.Platform.X11;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Ava.Ui
|
||||
{
|
||||
public class VulkanEmbeddedWindow : EmbeddedWindow
|
||||
{
|
||||
private NativeWindowBase _window;
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
protected override IPlatformHandle CreateLinux(IPlatformHandle parent)
|
||||
{
|
||||
X11Window = new GLXWindow(new NativeHandle(X11.DefaultDisplay), new NativeHandle(parent.Handle));
|
||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||
|
||||
X11Window.Hide();
|
||||
|
||||
return new PlatformHandle(WindowHandle, "X11");
|
||||
}
|
||||
|
||||
public SurfaceKHR CreateSurface(Instance instance)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
_window = new SimpleWin32Window(new NativeHandle(WindowHandle));
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
_window = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, _window));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Models
|
||||
{
|
||||
public class Amiibo
|
||||
{
|
||||
public struct AmiiboJson
|
||||
{
|
||||
[JsonPropertyName("amiibo")] public List<AmiiboApi> Amiibo { get; set; }
|
||||
[JsonPropertyName("lastUpdated")] public DateTime LastUpdated { get; set; }
|
||||
}
|
||||
|
||||
public struct AmiiboApi
|
||||
{
|
||||
[JsonPropertyName("name")] public string Name { get; set; }
|
||||
[JsonPropertyName("head")] public string Head { get; set; }
|
||||
[JsonPropertyName("tail")] public string Tail { get; set; }
|
||||
[JsonPropertyName("image")] public string Image { get; set; }
|
||||
[JsonPropertyName("amiiboSeries")] public string AmiiboSeries { get; set; }
|
||||
[JsonPropertyName("character")] public string Character { get; set; }
|
||||
[JsonPropertyName("gameSeries")] public string GameSeries { get; set; }
|
||||
[JsonPropertyName("type")] public string Type { get; set; }
|
||||
|
||||
[JsonPropertyName("release")] public Dictionary<string, string> Release { get; set; }
|
||||
|
||||
[JsonPropertyName("gamesSwitch")] public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public string GetId()
|
||||
{
|
||||
return Head + Tail;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is AmiiboApi amiibo)
|
||||
{
|
||||
return amiibo.Head + amiibo.Tail == Head + Tail;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class AmiiboApiGamesSwitch
|
||||
{
|
||||
[JsonPropertyName("amiiboUsage")] public List<AmiiboApiUsage> AmiiboUsage { get; set; }
|
||||
|
||||
[JsonPropertyName("gameID")] public List<string> GameId { get; set; }
|
||||
|
||||
[JsonPropertyName("gameName")] public string GameName { get; set; }
|
||||
}
|
||||
|
||||
public class AmiiboApiUsage
|
||||
{
|
||||
[JsonPropertyName("Usage")] public string Usage { get; set; }
|
||||
|
||||
[JsonPropertyName("write")] public bool Write { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Models.Generic
|
||||
{
|
||||
internal class LastPlayedSortComparer : IComparer<ApplicationData>
|
||||
{
|
||||
public LastPlayedSortComparer() { }
|
||||
public LastPlayedSortComparer(bool isAscending) { IsAscending = isAscending; }
|
||||
|
||||
public bool IsAscending { get; }
|
||||
|
||||
public int Compare(ApplicationData x, ApplicationData y)
|
||||
{
|
||||
string aValue = x.LastPlayed;
|
||||
string bValue = y.LastPlayed;
|
||||
|
||||
if (aValue == LocaleManager.Instance["Never"])
|
||||
{
|
||||
aValue = DateTime.UnixEpoch.ToString();
|
||||
}
|
||||
|
||||
if (bValue == LocaleManager.Instance["Never"])
|
||||
{
|
||||
bValue = DateTime.UnixEpoch.ToString();
|
||||
}
|
||||
|
||||
return (IsAscending ? 1 : -1) * DateTime.Compare(DateTime.Parse(bValue), DateTime.Parse(aValue));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
namespace Ryujinx.Ava.Ui.Models
|
||||
{
|
||||
public class ProfileImageModel
|
||||
{
|
||||
public ProfileImageModel(string name, byte[] data)
|
||||
{
|
||||
Name = name;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using LibHac.Ns;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Models
|
||||
{
|
||||
internal class TitleUpdateModel
|
||||
{
|
||||
public bool IsEnabled { get; set; }
|
||||
public bool IsNoUpdate { get; }
|
||||
public ApplicationControlProperty Control { get; }
|
||||
public string Path { get; }
|
||||
|
||||
public string Label => IsNoUpdate
|
||||
? LocaleManager.Instance["NoUpdate"]
|
||||
: string.Format(LocaleManager.Instance["TitleUpdateVersionLabel"], Control.DisplayVersionString.ToString(),
|
||||
Path);
|
||||
|
||||
public TitleUpdateModel(ApplicationControlProperty control, string path, bool isNoUpdate = false)
|
||||
{
|
||||
Control = control;
|
||||
Path = path;
|
||||
IsNoUpdate = isNoUpdate;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,213 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
public class UserProfileViewModel : BaseModel, IDisposable
|
||||
{
|
||||
private readonly NavigationDialogHost _owner;
|
||||
|
||||
private UserProfile _selectedProfile;
|
||||
private UserProfile _highlightedProfile;
|
||||
|
||||
public UserProfileViewModel()
|
||||
{
|
||||
Profiles = new ObservableCollection<UserProfile>();
|
||||
LostProfiles = new ObservableCollection<UserProfile>();
|
||||
}
|
||||
|
||||
public UserProfileViewModel(NavigationDialogHost owner) : this()
|
||||
{
|
||||
_owner = owner;
|
||||
|
||||
LoadProfiles();
|
||||
}
|
||||
|
||||
public ObservableCollection<UserProfile> Profiles { get; set; }
|
||||
|
||||
public ObservableCollection<UserProfile> LostProfiles { get; set; }
|
||||
|
||||
public UserProfile SelectedProfile
|
||||
{
|
||||
get => _selectedProfile;
|
||||
set
|
||||
{
|
||||
_selectedProfile = value;
|
||||
|
||||
OnPropertyChanged(nameof(SelectedProfile));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileEditable));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHighlightedProfileEditable => _highlightedProfile != null;
|
||||
|
||||
public bool IsHighlightedProfileDeletable => _highlightedProfile != null && _highlightedProfile.UserId != AccountManager.DefaultUserId;
|
||||
|
||||
public UserProfile HighlightedProfile
|
||||
{
|
||||
get => _highlightedProfile;
|
||||
set
|
||||
{
|
||||
_highlightedProfile = value;
|
||||
|
||||
OnPropertyChanged(nameof(HighlightedProfile));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileEditable));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public void LoadProfiles()
|
||||
{
|
||||
Profiles.Clear();
|
||||
LostProfiles.Clear();
|
||||
|
||||
var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
|
||||
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
Profiles.Add(new UserProfile(profile, _owner));
|
||||
}
|
||||
|
||||
SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
|
||||
|
||||
if (SelectedProfile == null)
|
||||
{
|
||||
SelectedProfile = Profiles.First();
|
||||
|
||||
if (SelectedProfile != null)
|
||||
{
|
||||
_owner.AccountManager.OpenUser(_selectedProfile.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
|
||||
default, saveDataId: default, index: default);
|
||||
|
||||
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||
|
||||
_owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
||||
|
||||
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||
|
||||
HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new HashSet<HLE.HOS.Services.Account.Acc.UserId>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
||||
|
||||
if (readCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < readCount; i++)
|
||||
{
|
||||
var save = saveDataInfo[i];
|
||||
var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
|
||||
if (Profiles.FirstOrDefault( x=> x.UserId == id) == null)
|
||||
{
|
||||
lostAccounts.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var account in lostAccounts)
|
||||
{
|
||||
LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddUser()
|
||||
{
|
||||
UserProfile userProfile = null;
|
||||
|
||||
_owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
|
||||
}
|
||||
|
||||
public async void ManageSaves()
|
||||
{
|
||||
UserProfile userProfile = _highlightedProfile ?? SelectedProfile;
|
||||
|
||||
SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem);
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
|
||||
PrimaryButtonText = "",
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||
Content = manager,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
|
||||
public void EditUser()
|
||||
{
|
||||
_owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
|
||||
}
|
||||
|
||||
public async void DeleteUser()
|
||||
{
|
||||
if (_highlightedProfile != null)
|
||||
{
|
||||
var lastUserId = _owner.AccountManager.LastOpenedUser.UserId;
|
||||
|
||||
if (_highlightedProfile.UserId == lastUserId)
|
||||
{
|
||||
// If we are deleting the currently open profile, then we must open something else before deleting.
|
||||
var profile = Profiles.FirstOrDefault(x => x.UserId != lastUserId);
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_owner.AccountManager.OpenUser(profile.UserId);
|
||||
}
|
||||
|
||||
var result =
|
||||
await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
_owner.AccountManager.DeleteUser(_highlightedProfile.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
LoadProfiles();
|
||||
}
|
||||
|
||||
public void GoBack()
|
||||
{
|
||||
_owner.GoBack();
|
||||
}
|
||||
|
||||
public void RecoverLostAccounts()
|
||||
{
|
||||
_owner.Navigate(typeof(UserRecoverer), (this._owner, this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,282 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.AboutWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Width="850"
|
||||
Height="550"
|
||||
MinWidth="500"
|
||||
MinHeight="550"
|
||||
d:DesignHeight="350"
|
||||
d:DesignWidth="400"
|
||||
CanResize="False"
|
||||
SizeToContent="Width"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid
|
||||
Margin="15"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="0"
|
||||
Height="110"
|
||||
MinWidth="50"
|
||||
Margin="5,10,20,10"
|
||||
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,20,0,0"
|
||||
FontSize="35"
|
||||
Text="Ryujinx"
|
||||
TextAlignment="Center" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,0,0"
|
||||
FontSize="16"
|
||||
Text="(REE-YOU-JINX)"
|
||||
TextAlignment="Center" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://www.ryujinx.org/">
|
||||
<TextBlock
|
||||
Text="www.ryujinx.org"
|
||||
TextAlignment="Center"
|
||||
TextDecorations="Underline"
|
||||
ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Version}"
|
||||
TextAlignment="Center" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Center"
|
||||
MaxLines="2"
|
||||
Text="{locale:Locale AboutDisclaimerMessage}"
|
||||
TextAlignment="Center" />
|
||||
<TextBlock
|
||||
Name="AmiiboLabel"
|
||||
Grid.Row="3"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Center"
|
||||
MaxLines="2"
|
||||
PointerPressed="AmiiboLabel_OnPointerPressed"
|
||||
Text="{locale:Locale AboutAmiiboDisclaimerMessage}"
|
||||
TextAlignment="Center" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}">
|
||||
<Button
|
||||
Height="65"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://www.patreon.com/ryujinx">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Patreon.png?assembly=Ryujinx.Ui.Common" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Patreon" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}">
|
||||
<Button
|
||||
Height="65"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://github.com/Ryujinx/Ryujinx">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_GitHub.png?assembly=Ryujinx.Ui.Common" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="GitHub" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}">
|
||||
<Button
|
||||
Height="65"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://discordapp.com/invite/N2FmfVc">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Discord.png?assembly=Ryujinx.Ui.Common" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Discord" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}">
|
||||
<Button
|
||||
Height="65"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://twitter.com/RyujinxEmu">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Twitter.png?assembly=Ryujinx.Ui.Common" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Twitter" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="2"
|
||||
Margin="5"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="White"
|
||||
BorderThickness="1,0,0,0">
|
||||
<Separator Width="0" />
|
||||
</Border>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
FontWeight="Bold"
|
||||
Text="{locale:Locale AboutRyujinxAboutTitle}"
|
||||
TextDecorations="Underline" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="20,5,5,5"
|
||||
LineHeight="20"
|
||||
Text="{locale:Locale AboutRyujinxAboutContent}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="0,10,0,0"
|
||||
FontWeight="Bold"
|
||||
Text="{locale:Locale AboutRyujinxMaintainersTitle}"
|
||||
TextDecorations="Underline" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Margin="20,5,5,5"
|
||||
LineHeight="20"
|
||||
Text="{Binding Developers}" />
|
||||
<Button
|
||||
Grid.Row="4"
|
||||
HorizontalAlignment="Right"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a">
|
||||
<TextBlock
|
||||
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
||||
TextAlignment="Right"
|
||||
TextDecorations="Underline"
|
||||
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Margin="0,0,0,0"
|
||||
FontWeight="Bold"
|
||||
Text="{locale:Locale AboutRyujinxSupprtersTitle}"
|
||||
TextDecorations="Underline" />
|
||||
<Border
|
||||
Grid.Row="6"
|
||||
Width="460"
|
||||
Height="200"
|
||||
Margin="20,5"
|
||||
Padding="5"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="White"
|
||||
BorderThickness="1">
|
||||
<TextBlock
|
||||
Name="SupportersTextBlock"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding Supporters}"
|
||||
TextWrapping="Wrap" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@ -1,78 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class AboutWindow : StyleableWindow
|
||||
{
|
||||
public AboutWindow()
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["MenuBarHelpAbout"];
|
||||
}
|
||||
|
||||
Version = Program.Version;
|
||||
|
||||
DataContext = this;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
_ = DownloadPatronsJson();
|
||||
}
|
||||
|
||||
public string Supporters { get; set; }
|
||||
public string Version { get; set; }
|
||||
|
||||
public string Developers => string.Format(LocaleManager.Instance["AboutPageDeveloperListMore"], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
|
||||
|
||||
private void Button_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
OpenHelper.OpenUrl(button.Tag.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadPatronsJson()
|
||||
{
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
Supporters = LocaleManager.Instance["ConnectionError"];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HttpClient httpClient = new();
|
||||
|
||||
try
|
||||
{
|
||||
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
||||
|
||||
Supporters = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Supporters = LocaleManager.Instance["ApiError"];
|
||||
}
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() => SupportersTextBlock.Text = Supporters);
|
||||
}
|
||||
|
||||
private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is TextBlock)
|
||||
{
|
||||
OpenHelper.OpenUrl("https://amiiboapi.com");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="350"
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.AvatarWindow"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:AvatarProfileViewModel"
|
||||
Focusable="True">
|
||||
<Design.DataContext>
|
||||
<viewModels:AvatarProfileViewModel />
|
||||
</Design.DataContext>
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox Grid.Row="1" BorderThickness="0" SelectedIndex="{Binding SelectedIndex}" Height="400"
|
||||
Items="{Binding Images}" HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" MaxWidth="700" Margin="0" HorizontalAlignment="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Image Margin="5" Height="96" Width="96"
|
||||
Source="{Binding Data, Converter={StaticResource ByteImage}}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<ProgressBar Grid.Row="2" IsIndeterminate="{Binding IsIndeterminate}" Value="{Binding ImagesLoaded}" HorizontalAlignment="Stretch" Margin="5"
|
||||
Maximum="{Binding ImageCount}" Minimum="0" />
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" Spacing="10" Margin="10" HorizontalAlignment="Center">
|
||||
<Button Content="{Locale:Locale AvatarChoose}" Width="200" Name="ChooseButton" Click="ChooseButton_OnClick" />
|
||||
<ui:ColorPickerButton Color="{Binding BackgroundColor, Mode=TwoWay}" Name="ColorButton" />
|
||||
<Button HorizontalAlignment="Right" Content="{Locale:Locale Discard}" Click="CloseButton_OnClick"
|
||||
Name="CloseButton"
|
||||
Width="200" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,28 +0,0 @@
|
||||
<window:StyleableWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.ContentDialogOverlayWindow"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Title="ContentDialogOverlayWindow"
|
||||
Focusable="True">
|
||||
<window:StyleableWindow.Styles>
|
||||
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
|
||||
<Setter Property="Background"
|
||||
Value="Transparent" />
|
||||
</Style>
|
||||
</window:StyleableWindow.Styles>
|
||||
<ContentControl
|
||||
Focusable="False"
|
||||
IsVisible="False"
|
||||
KeyboardNavigation.IsTabStop="False">
|
||||
<ui:ContentDialog Name="ContentDialog"
|
||||
IsPrimaryButtonEnabled="True"
|
||||
IsSecondaryButtonEnabled="True"
|
||||
IsVisible="False" />
|
||||
</ContentControl>
|
||||
</window:StyleableWindow>
|
@ -1,172 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.DownloadableContentManagerWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Width="800"
|
||||
Height="500"
|
||||
MinWidth="800"
|
||||
MinHeight="500"
|
||||
MaxWidth="800"
|
||||
MaxHeight="500"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid Name="DownloadableContentGrid" Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Name="Heading"
|
||||
Grid.Row="1"
|
||||
MaxWidth="500"
|
||||
Margin="20,15,20,20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
LineHeight="18"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
<DockPanel
|
||||
Grid.Row="2"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left">
|
||||
<Button
|
||||
Name="EnableAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding EnableAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="DisableAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding DisableAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
<Border
|
||||
Grid.Row="3"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1">
|
||||
<ScrollViewer
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid
|
||||
Name="DlcDataGrid"
|
||||
MinHeight="200"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserSortColumns="True"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
Items="{Binding _downloadableContents}"
|
||||
SelectionMode="Extended"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Styles>
|
||||
<Styles>
|
||||
<Style Selector="DataGridCell:nth-child(3), DataGridCell:nth-child(4)">
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
</Style>
|
||||
</Styles>
|
||||
<Styles>
|
||||
<Style Selector="DataGridCell:nth-child(1)">
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
||||
</Style>
|
||||
</Styles>
|
||||
</DataGrid.Styles>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="90">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox
|
||||
Width="50"
|
||||
MinWidth="40"
|
||||
HorizontalAlignment="Center"
|
||||
IsChecked="{Binding Enabled}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Width="140" Binding="{Binding TitleId}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="280" Binding="{Binding FullPath}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Binding="{Binding ContainerPath}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<DockPanel
|
||||
Grid.Row="4"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch">
|
||||
<DockPanel Margin="0" HorizontalAlignment="Left">
|
||||
<Button
|
||||
Name="AddButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding Add}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding RemoveSelected}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding RemoveAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
<DockPanel Margin="0" HorizontalAlignment="Right">
|
||||
<Button
|
||||
Name="SaveButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding SaveAndClose}">
|
||||
<TextBlock Text="{locale:Locale SettingsButtonSave}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="CancelButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding Close}">
|
||||
<TextBlock Text="{locale:Locale InputDialogCancel}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@ -1,770 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.MainWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Title="Ryujinx"
|
||||
Width="1280"
|
||||
Height="777"
|
||||
MinWidth="1092"
|
||||
MinHeight="672"
|
||||
d:DesignHeight="720"
|
||||
d:DesignWidth="1280"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:MainWindowViewModel"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Window.Styles>
|
||||
<Style Selector="TitleBar:fullscreen">
|
||||
<Setter Property="Background" Value="#000000" />
|
||||
</Style>
|
||||
</Window.Styles>
|
||||
<Design.DataContext>
|
||||
<viewModels:MainWindowViewModel />
|
||||
</Design.DataContext>
|
||||
<Window.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</Window.Resources>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<controls:OffscreenTextBox Name="HiddenTextBox" Grid.Row="0" />
|
||||
<StackPanel Grid.Row="0" IsVisible="False">
|
||||
<controls:HotKeyControl Name="FullscreenHotKey" Command="{ReflectionBinding ToggleFullscreen}" />
|
||||
<controls:HotKeyControl Name="FullscreenHotKey2" Command="{ReflectionBinding ToggleFullscreen}" />
|
||||
<controls:HotKeyControl Name="DockToggleHotKey" Command="{ReflectionBinding ToggleDockMode}" />
|
||||
<controls:HotKeyControl Name="ExitHotKey" Command="{ReflectionBinding ExitCurrentState}" />
|
||||
</StackPanel>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel
|
||||
Name="MenuBar"
|
||||
MinHeight="35"
|
||||
Grid.Row="0"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="{Binding ShowMenuAndStatusBar}"
|
||||
Orientation="Vertical">
|
||||
<DockPanel HorizontalAlignment="Stretch">
|
||||
<Menu
|
||||
Name="Menu"
|
||||
Height="35"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left">
|
||||
<Menu.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<DockPanel Margin="0" HorizontalAlignment="Stretch" />
|
||||
</ItemsPanelTemplate>
|
||||
</Menu.ItemsPanel>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenFile}"
|
||||
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenFolder}"
|
||||
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
||||
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenMiiApplet}"
|
||||
Header="Mii Edit Applet"
|
||||
ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenRyujinxFolder}"
|
||||
Header="{locale:Locale MenuBarFileOpenEmuFolder}"
|
||||
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenLogsFolder}"
|
||||
Header="{locale:Locale MenuBarFileOpenLogsFolder}"
|
||||
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding CloseWindow}"
|
||||
Header="{locale:Locale MenuBarFileExit}"
|
||||
ToolTip.Tip="{locale:Locale ExitTooltip}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ToggleFullscreen}"
|
||||
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
||||
InputGesture="F11" />
|
||||
<MenuItem>
|
||||
<MenuItem.Icon>
|
||||
<CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
||||
MinWidth="250">
|
||||
<TextBlock Text="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"/>
|
||||
</CheckBox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem IsVisible="{Binding ShowConsoleVisible}">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
||||
MinWidth="250">
|
||||
<TextBlock Text="{locale:Locale MenuBarOptionsShowConsole}"/>
|
||||
</CheckBox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}">
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="de_DE"
|
||||
Header="Deutsch" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="en_US"
|
||||
Header="English (US)" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="es_ES"
|
||||
Header="Español (ES)" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="fr_FR"
|
||||
Header="Français" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="it_IT"
|
||||
Header="Italiano" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="pt_BR"
|
||||
Header="Português (BR)" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="tr_TR"
|
||||
Header="Türkçe" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="el_GR"
|
||||
Header="Ελληνικά" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="pl_PL"
|
||||
Header="Polski" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="ru_RU"
|
||||
Header="Русский" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="zh_CN"
|
||||
Header="简体中文" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="zh_TW"
|
||||
Header="繁體中文" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="ja_JP"
|
||||
Header="日本語" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ChangeLanguage}"
|
||||
CommandParameter="ko_KR"
|
||||
Header="한국어" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenSettings}"
|
||||
Header="{locale:Locale MenuBarOptionsSettings}"
|
||||
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding ManageProfiles}"
|
||||
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Name="ActionsMenuItem"
|
||||
VerticalAlignment="Center"
|
||||
Header="{locale:Locale MenuBarActions}"
|
||||
IsEnabled="{Binding IsGameRunning}">
|
||||
<MenuItem
|
||||
Click="PauseEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsPauseEmulation}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding !IsPaused}"
|
||||
IsVisible="{Binding !IsPaused}" />
|
||||
<MenuItem
|
||||
Click="ResumeEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsResumeEmulation}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding IsPaused}"
|
||||
IsVisible="{Binding IsPaused}" />
|
||||
<MenuItem
|
||||
Click="StopEmulation_Click"
|
||||
Header="{locale:Locale MenuBarOptionsStopEmulation}"
|
||||
InputGesture="Escape"
|
||||
IsEnabled="{Binding IsGameRunning}"
|
||||
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
||||
<MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Name="ScanAmiiboMenuItem"
|
||||
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
||||
Command="{ReflectionBinding OpenAmiiboWindow}"
|
||||
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding TakeScreenshot}"
|
||||
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
||||
InputGesture="{Binding ScreenshotKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding HideUi}"
|
||||
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
||||
InputGesture="{Binding ShowUiKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenCheatManagerForCurrentApp}"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
|
||||
<MenuItem
|
||||
Name="UpdateMenuItem"
|
||||
Command="{ReflectionBinding CheckForUpdates}"
|
||||
Header="{locale:Locale MenuBarHelpCheckForUpdates}"
|
||||
ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{ReflectionBinding OpenAboutWindow}"
|
||||
Header="{locale:Locale MenuBarHelpAbout}"
|
||||
ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
<ContentControl
|
||||
Name="MainContent"
|
||||
Grid.Row="1"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource ThemeControlBorderColor}"
|
||||
BorderThickness="0,0,0,0"
|
||||
DockPanel.Dock="Top"
|
||||
IsVisible="{Binding ShowContent}">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,5"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Button
|
||||
Width="40"
|
||||
MinWidth="40"
|
||||
Margin="5,2,0,2"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{ReflectionBinding SetListMode}"
|
||||
IsEnabled="{Binding IsGrid}">
|
||||
<ui:FontIcon
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||
Glyph="{controls:GlyphValueConverter List}" />
|
||||
</Button>
|
||||
<Button
|
||||
Width="40"
|
||||
MinWidth="40"
|
||||
Margin="5,2,5,2"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{ReflectionBinding SetGridMode}"
|
||||
IsEnabled="{Binding IsList}">
|
||||
<ui:FontIcon
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||
Glyph="{controls:GlyphValueConverter Grid}" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{locale:Locale IconSize}"
|
||||
ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
|
||||
<Slider
|
||||
Width="150"
|
||||
Height="35"
|
||||
Margin="5,-10,5,0"
|
||||
VerticalAlignment="Center"
|
||||
IsSnapToTickEnabled="True"
|
||||
Maximum="4"
|
||||
Minimum="1"
|
||||
TickFrequency="1"
|
||||
ToolTip.Tip="{locale:Locale IconSizeTooltip}"
|
||||
Value="{Binding GridSizeScale}" />
|
||||
<CheckBox
|
||||
Margin="0"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding ShowNames, Mode=TwoWay}"
|
||||
IsVisible="{Binding IsGrid}">
|
||||
<TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" />
|
||||
</CheckBox>
|
||||
<TextBox
|
||||
Name="SearchBox"
|
||||
MinWidth="200"
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Right"
|
||||
KeyUp="SearchBox_OnKeyUp"
|
||||
Text="{Binding SearchText}"
|
||||
Watermark="{locale:Locale MenuSearch}" />
|
||||
<ui:DropDownButton
|
||||
Width="150"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Content="{Binding SortName}"
|
||||
DockPanel.Dock="Right">
|
||||
<ui:DropDownButton.Flyout>
|
||||
<Flyout Placement="Bottom">
|
||||
<StackPanel
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<StackPanel>
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale CommonFavorite}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}"
|
||||
Tag="Favorite" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderApplication}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
|
||||
Tag="Title" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderDeveloper}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}"
|
||||
Tag="Developer" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderTimePlayed}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}"
|
||||
Tag="TotalTimePlayed" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderLastPlayed}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}"
|
||||
Tag="LastPlayed" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderFileExtension}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByType, Mode=OneTime}"
|
||||
Tag="FileType" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderFileSize}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedBySize, Mode=OneTime}"
|
||||
Tag="FileSize" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{locale:Locale GameListHeaderPath}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByPath, Mode=OneTime}"
|
||||
Tag="Path" />
|
||||
</StackPanel>
|
||||
<Border
|
||||
Width="60"
|
||||
Height="2"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="White"
|
||||
BorderThickness="0,1,0,0">
|
||||
<Separator Height="0" HorizontalAlignment="Stretch" />
|
||||
</Border>
|
||||
<RadioButton
|
||||
Checked="Order_Checked"
|
||||
Content="{locale:Locale OrderAscending}"
|
||||
GroupName="Order"
|
||||
IsChecked="{Binding IsAscending, Mode=OneTime}"
|
||||
Tag="Ascending" />
|
||||
<RadioButton
|
||||
Checked="Order_Checked"
|
||||
Content="{locale:Locale OrderDescending}"
|
||||
GroupName="Order"
|
||||
IsChecked="{Binding !IsAscending, Mode=OneTime}"
|
||||
Tag="Descending" />
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</ui:DropDownButton.Flyout>
|
||||
</ui:DropDownButton>
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Right"
|
||||
Text="{locale:Locale CommonSort}" />
|
||||
</DockPanel>
|
||||
<controls:GameListView
|
||||
x:Name="GameList"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsVisible="{Binding IsList}" />
|
||||
<controls:GameGridView
|
||||
x:Name="GameGrid"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsVisible="{Binding IsGrid}" />
|
||||
</Grid>
|
||||
</ContentControl>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Name="LoadingView"
|
||||
ZIndex="1000">
|
||||
<Grid
|
||||
Margin="40"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding ShowLoadProgress}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Width="256"
|
||||
Height="256"
|
||||
Margin="10"
|
||||
Padding="4"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
BoxShadow="4 4 32 8 #40000000"
|
||||
CornerRadius="3"
|
||||
IsVisible="{Binding ShowLoadProgress}">
|
||||
<Image
|
||||
Width="256"
|
||||
Height="256"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" />
|
||||
</Border>
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding ShowLoadProgress}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="10"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Text="{Binding LoadHeading}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Margin="10"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="{Binding ProgressBarBackgroundColor}"
|
||||
BorderThickness="1"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5"
|
||||
IsVisible="{Binding ShowLoadProgress}">
|
||||
<ProgressBar
|
||||
Height="10"
|
||||
MinWidth="500"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{Binding ProgressBarBackgroundColor}"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5"
|
||||
Foreground="{Binding ProgressBarForegroundColor}"
|
||||
IsIndeterminate="{Binding IsLoadingIndeterminate}"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Maximum="{Binding ProgressMaximum}"
|
||||
Minimum="0"
|
||||
Value="{Binding ProgressValue}" />
|
||||
</Border>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="10"
|
||||
FontSize="18"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Text="{Binding CacheLoadStatus}"
|
||||
TextAlignment="Left" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
Name="StatusBar"
|
||||
Grid.Row="2"
|
||||
Margin="0"
|
||||
MinHeight="22"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||
DockPanel.Dock="Bottom"
|
||||
IsVisible="{Binding ShowMenuAndStatusBar}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding EnableNonGameRunningControls}">
|
||||
<Grid Margin="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
Width="25"
|
||||
Height="25"
|
||||
MinWidth="0"
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Command="{ReflectionBinding LoadApplications}">
|
||||
<ui:SymbolIcon
|
||||
Width="50"
|
||||
Height="100"
|
||||
Symbol="Refresh" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Name="LoadStatus"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding EnableNonGameRunningControls}"
|
||||
Text="{locale:Locale StatusBarGamesLoaded}" />
|
||||
<ProgressBar
|
||||
Name="LoadProgressBar"
|
||||
Grid.Column="2"
|
||||
Height="6"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource HighlightColor}"
|
||||
IsVisible="{Binding EnableNonGameRunningControls}"
|
||||
Maximum="{Binding StatusBarProgressMaximum}"
|
||||
Value="{Binding StatusBarProgressValue}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
Margin="0,2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsGameRunning}"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Name="VsyncStatus"
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{Binding VsyncColor}"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
PointerReleased="VsyncStatus_PointerReleased"
|
||||
Text="VSync"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Name="DockedStatus"
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
PointerReleased="DockedStatus_PointerReleased"
|
||||
Text="{Binding DockedStatusText}"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Name="AspectRatioStatus"
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
PointerReleased="AspectRatioStatus_PointerReleased"
|
||||
Text="{Binding AspectRatioStatusText}"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<ui:ToggleSplitButton
|
||||
Name="VolumeStatus"
|
||||
Padding="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||
BorderThickness="0"
|
||||
Content="{Binding VolumeStatusText}"
|
||||
IsChecked="{Binding VolumeMuted}"
|
||||
IsVisible="{Binding !ShowLoadProgress}">
|
||||
<ui:ToggleSplitButton.Flyout>
|
||||
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||
<Grid Margin="0">
|
||||
<Slider
|
||||
MaxHeight="40"
|
||||
Width="150"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
IsSnapToTickEnabled="True"
|
||||
LargeChange="0.05"
|
||||
Maximum="1"
|
||||
Minimum="0"
|
||||
SmallChange="0.01"
|
||||
TickFrequency="0.05"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Value="{Binding Volume}" />
|
||||
</Grid>
|
||||
</Flyout>
|
||||
</ui:ToggleSplitButton.Flyout>
|
||||
</ui:ToggleSplitButton>
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding GameStatusText}"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding FifoStatusText}"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding BackendText}"
|
||||
TextAlignment="Left" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
Margin="0"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
IsVisible="{Binding !ShowLoadProgress}" />
|
||||
<TextBlock
|
||||
Margin="5,0,5,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding GpuNameText}"
|
||||
TextAlignment="Left" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="3"
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding ShowFirmwareStatus}"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Name="FirmwareStatus"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="{locale:Locale StatusBarSystemVersion}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@ -1,720 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Input;
|
||||
using Ryujinx.Ava.Ui.Applet;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.Input.SDL2;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class MainWindow : StyleableWindow
|
||||
{
|
||||
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
|
||||
private bool _canUpdate;
|
||||
private bool _isClosing;
|
||||
private bool _isLoading;
|
||||
|
||||
private Control _mainViewContent;
|
||||
|
||||
private UserChannelPersistence _userChannelPersistence;
|
||||
private static bool _deferLoad;
|
||||
private static string _launchPath;
|
||||
private static bool _startFullscreen;
|
||||
private string _currentEmulatedGamePath;
|
||||
internal readonly AvaHostUiHandler UiHandler;
|
||||
private AutoResetEvent _rendererWaitEvent;
|
||||
|
||||
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
||||
public ContentManager ContentManager { get; private set; }
|
||||
public AccountManager AccountManager { get; private set; }
|
||||
|
||||
public LibHacHorizonManager LibHacHorizonManager { get; private set; }
|
||||
|
||||
internal AppHost AppHost { get; private set; }
|
||||
public InputManager InputManager { get; private set; }
|
||||
|
||||
internal RendererHost RendererControl { get; private set; }
|
||||
internal MainWindowViewModel ViewModel { get; private set; }
|
||||
public SettingsWindow SettingsWindow { get; set; }
|
||||
|
||||
public bool CanUpdate
|
||||
{
|
||||
get => _canUpdate;
|
||||
set
|
||||
{
|
||||
_canUpdate = value;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() => UpdateMenuItem.IsEnabled = _canUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ShowKeyErrorOnLoad { get; set; }
|
||||
public ApplicationLibrary ApplicationLibrary { get; set; }
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
ViewModel = new MainWindowViewModel(this);
|
||||
|
||||
MainWindowViewModel = ViewModel;
|
||||
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
|
||||
UiHandler = new AvaHostUiHandler(this);
|
||||
|
||||
Title = $"Ryujinx {Program.Version}";
|
||||
|
||||
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
||||
double barHeight = MenuBar.MinHeight + StatusBar.MinHeight;
|
||||
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
|
||||
Width /= Program.WindowScaleFactor;
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
ViewModel.Initialize();
|
||||
|
||||
InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver());
|
||||
|
||||
LoadGameList();
|
||||
}
|
||||
|
||||
_rendererWaitEvent = new AutoResetEvent(false);
|
||||
}
|
||||
|
||||
public void LoadGameList()
|
||||
{
|
||||
if (_isLoading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
|
||||
ViewModel.LoadApplications();
|
||||
|
||||
_isLoading = false;
|
||||
}
|
||||
|
||||
private void Update_StatusBar(object sender, StatusUpdatedEventArgs args)
|
||||
{
|
||||
if (ViewModel.ShowMenuAndStatusBar && !ViewModel.ShowLoadProgress)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
if (args.VSyncEnabled)
|
||||
{
|
||||
ViewModel.VsyncColor = new SolidColorBrush(Color.Parse("#ff2eeac9"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel.VsyncColor = new SolidColorBrush(Color.Parse("#ffff4554"));
|
||||
}
|
||||
|
||||
ViewModel.DockedStatusText = args.DockedMode;
|
||||
ViewModel.AspectRatioStatusText = args.AspectRatio;
|
||||
ViewModel.GameStatusText = args.GameStatus;
|
||||
ViewModel.VolumeStatusText = args.VolumeStatus;
|
||||
ViewModel.FifoStatusText = args.FifoStatus;
|
||||
ViewModel.GpuNameText = args.GpuName;
|
||||
ViewModel.BackendText = args.GpuBackend;
|
||||
|
||||
ViewModel.ShowStatusSeparator = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleScalingChanged(double scale)
|
||||
{
|
||||
Program.DesktopScaleFactor = scale;
|
||||
base.HandleScalingChanged(scale);
|
||||
}
|
||||
|
||||
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
||||
{
|
||||
if (args.Application != null)
|
||||
{
|
||||
ViewModel.SelectedIcon = args.Application.Icon;
|
||||
|
||||
string path = new FileInfo(args.Application.Path).FullName;
|
||||
|
||||
LoadApplication(path);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public async Task PerformanceCheck()
|
||||
{
|
||||
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
|
||||
{
|
||||
string mainMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledMessage"];
|
||||
string secondaryMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledConfirmMessage"];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
ConfigurationState.Instance.Logger.EnableTrace.Value = false;
|
||||
|
||||
SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
|
||||
{
|
||||
string mainMessage = LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledMessage"];
|
||||
string secondaryMessage =
|
||||
LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledConfirmMessage"];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = "";
|
||||
|
||||
SaveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DeferLoadApplication(string launchPathArg, bool startFullscreenArg)
|
||||
{
|
||||
_deferLoad = true;
|
||||
_launchPath = launchPathArg;
|
||||
_startFullscreen = startFullscreenArg;
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998
|
||||
public async void LoadApplication(string path, bool startFullscreen = false, string titleName = "")
|
||||
#pragma warning restore CS1998
|
||||
{
|
||||
if (AppHost != null)
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedMessage"],
|
||||
LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedSubMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if RELEASE
|
||||
await PerformanceCheck();
|
||||
#endif
|
||||
|
||||
Logger.RestartTime();
|
||||
|
||||
if (ViewModel.SelectedIcon == null)
|
||||
{
|
||||
ViewModel.SelectedIcon = ApplicationLibrary.GetApplicationIcon(path);
|
||||
}
|
||||
|
||||
PrepareLoadScreen();
|
||||
|
||||
_mainViewContent = MainContent.Content as Control;
|
||||
|
||||
RendererControl = new RendererHost(ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl)
|
||||
{
|
||||
RendererControl.CreateOpenGL();
|
||||
}
|
||||
else
|
||||
{
|
||||
RendererControl.CreateVulkan();
|
||||
}
|
||||
|
||||
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
||||
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
if (!await AppHost.LoadGuestApplication())
|
||||
{
|
||||
AppHost.DisposeContext();
|
||||
AppHost = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CanUpdate = false;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
|
||||
SwitchToGameControl(startFullscreen);
|
||||
|
||||
_currentEmulatedGamePath = path;
|
||||
|
||||
Thread gameThread = new(InitializeGame)
|
||||
{
|
||||
Name = "GUI.WindowThread"
|
||||
};
|
||||
gameThread.Start();
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeGame()
|
||||
{
|
||||
RendererControl.RendererInitialized += GlRenderer_Created;
|
||||
|
||||
AppHost.StatusUpdatedEvent += Update_StatusBar;
|
||||
AppHost.AppExit += AppHost_AppExit;
|
||||
|
||||
_rendererWaitEvent.WaitOne();
|
||||
|
||||
AppHost?.Start();
|
||||
|
||||
AppHost.DisposeContext();
|
||||
}
|
||||
|
||||
|
||||
private void HandleRelaunch()
|
||||
{
|
||||
if (_userChannelPersistence.PreviousIndex != -1 && _userChannelPersistence.ShouldRestart)
|
||||
{
|
||||
_userChannelPersistence.ShouldRestart = false;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
LoadApplication(_currentEmulatedGamePath);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, clear state.
|
||||
_userChannelPersistence = new UserChannelPersistence();
|
||||
_currentEmulatedGamePath = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SwitchToGameControl(bool startFullscreen = false)
|
||||
{
|
||||
ViewModel.ShowLoadProgress = false;
|
||||
ViewModel.ShowContent = true;
|
||||
ViewModel.IsLoadingIndeterminate = false;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
MainContent.Content = RendererControl;
|
||||
|
||||
if (startFullscreen && WindowState != WindowState.FullScreen)
|
||||
{
|
||||
ViewModel.ToggleFullscreen();
|
||||
}
|
||||
|
||||
RendererControl.Focus();
|
||||
});
|
||||
}
|
||||
|
||||
public void ShowLoading(bool startFullscreen = false)
|
||||
{
|
||||
ViewModel.ShowContent = false;
|
||||
ViewModel.ShowLoadProgress = true;
|
||||
ViewModel.IsLoadingIndeterminate = true;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
if (startFullscreen && WindowState != WindowState.FullScreen)
|
||||
{
|
||||
ViewModel.ToggleFullscreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void GlRenderer_Created(object sender, EventArgs e)
|
||||
{
|
||||
ShowLoading();
|
||||
|
||||
_rendererWaitEvent.Set();
|
||||
}
|
||||
|
||||
private void AppHost_AppExit(object sender, EventArgs e)
|
||||
{
|
||||
if (_isClosing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.IsGameRunning = false;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
ViewModel.ShowMenuAndStatusBar = true;
|
||||
ViewModel.ShowContent = true;
|
||||
ViewModel.ShowLoadProgress = false;
|
||||
ViewModel.IsLoadingIndeterminate = false;
|
||||
CanUpdate = true;
|
||||
Cursor = Cursor.Default;
|
||||
|
||||
if (MainContent.Content != _mainViewContent)
|
||||
{
|
||||
MainContent.Content = _mainViewContent;
|
||||
}
|
||||
|
||||
AppHost = null;
|
||||
|
||||
HandleRelaunch();
|
||||
});
|
||||
|
||||
RendererControl.RendererInitialized -= GlRenderer_Created;
|
||||
RendererControl = null;
|
||||
|
||||
ViewModel.SelectedIcon = null;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version}";
|
||||
});
|
||||
}
|
||||
|
||||
public void Sort_Checked(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is RadioButton button)
|
||||
{
|
||||
var sort = Enum.Parse<ApplicationSort>(button.Tag.ToString());
|
||||
ViewModel.Sort(sort);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleWindowStateChanged(WindowState state)
|
||||
{
|
||||
WindowState = state;
|
||||
|
||||
if (state != WindowState.Minimized)
|
||||
{
|
||||
Renderer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Order_Checked(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is RadioButton button)
|
||||
{
|
||||
var tag = button.Tag.ToString();
|
||||
ViewModel.Sort(tag != "Descending");
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
_userChannelPersistence = new UserChannelPersistence();
|
||||
VirtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||
LibHacHorizonManager = new LibHacHorizonManager();
|
||||
ContentManager = new ContentManager(VirtualFileSystem);
|
||||
|
||||
LibHacHorizonManager.InitializeFsServer(VirtualFileSystem);
|
||||
LibHacHorizonManager.InitializeArpServer();
|
||||
LibHacHorizonManager.InitializeBcatServer();
|
||||
LibHacHorizonManager.InitializeSystemClients();
|
||||
|
||||
ApplicationLibrary = new ApplicationLibrary(VirtualFileSystem);
|
||||
|
||||
// Save data created before we supported extra data in directory save data will not work properly if
|
||||
// given empty extra data. Luckily some of that extra data can be created using the data from the
|
||||
// save data indexer, which should be enough to check access permissions for user saves.
|
||||
// Every single save data's extra data will be checked and fixed if needed each time the emulator is opened.
|
||||
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
||||
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
||||
|
||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
||||
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
|
||||
ApplicationHelper.Initialize(VirtualFileSystem, AccountManager, LibHacHorizonManager.RyujinxClient, this);
|
||||
|
||||
RefreshFirmwareStatus();
|
||||
}
|
||||
|
||||
protected void CheckLaunchState()
|
||||
{
|
||||
if (ShowKeyErrorOnLoad)
|
||||
{
|
||||
ShowKeyErrorOnLoad = false;
|
||||
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, this));
|
||||
}
|
||||
|
||||
if (_deferLoad)
|
||||
{
|
||||
_deferLoad = false;
|
||||
|
||||
LoadApplication(_launchPath, _startFullscreen);
|
||||
}
|
||||
|
||||
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false, this))
|
||||
{
|
||||
Updater.BeginParse(this, false).ContinueWith(task =>
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}");
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshFirmwareStatus()
|
||||
{
|
||||
SystemVersion version = null;
|
||||
try
|
||||
{
|
||||
version = ContentManager.GetCurrentFirmwareVersion();
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
bool hasApplet = false;
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion",
|
||||
version.VersionString);
|
||||
|
||||
hasApplet = version.Major > 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion", "0.0");
|
||||
}
|
||||
|
||||
ViewModel.IsAppletMenuActive = hasApplet;
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
VolumeStatus.Click += VolumeStatus_CheckedChanged;
|
||||
|
||||
GameGrid.ApplicationOpened += Application_Opened;
|
||||
|
||||
GameGrid.DataContext = ViewModel;
|
||||
|
||||
GameList.ApplicationOpened += Application_Opened;
|
||||
|
||||
GameList.DataContext = ViewModel;
|
||||
|
||||
LoadHotKeys();
|
||||
}
|
||||
|
||||
protected override void OnOpened(EventArgs e)
|
||||
{
|
||||
base.OnOpened(e);
|
||||
|
||||
CheckLaunchState();
|
||||
}
|
||||
|
||||
public static void UpdateGraphicsConfig()
|
||||
{
|
||||
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
|
||||
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
||||
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||
}
|
||||
|
||||
public void LoadHotKeys()
|
||||
{
|
||||
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
|
||||
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
|
||||
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
|
||||
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
||||
}
|
||||
|
||||
public static void SaveConfig()
|
||||
{
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||
}
|
||||
|
||||
public void UpdateGameMetadata(string titleId)
|
||||
{
|
||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||
{
|
||||
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
|
||||
{
|
||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
||||
|
||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void PrepareLoadScreen()
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream(ViewModel.SelectedIcon);
|
||||
using var gameIconBmp = SixLabors.ImageSharp.Image.Load<Bgra32>(stream);
|
||||
|
||||
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
|
||||
|
||||
const int ColorDivisor = 4;
|
||||
|
||||
Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B);
|
||||
Color progressBgColor = Color.FromRgb(
|
||||
(byte)(dominantColor.R / ColorDivisor),
|
||||
(byte)(dominantColor.G / ColorDivisor),
|
||||
(byte)(dominantColor.B / ColorDivisor));
|
||||
|
||||
ViewModel.ProgressBarForegroundColor = new SolidColorBrush(progressFgColor);
|
||||
ViewModel.ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor);
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
ViewModel.SearchText = SearchBox.Text;
|
||||
}
|
||||
|
||||
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (AppHost != null)
|
||||
{
|
||||
await AppHost.ShowExitPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
private async void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
AppHost?.Pause();
|
||||
});
|
||||
}
|
||||
|
||||
private async void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
AppHost?.Resume();
|
||||
});
|
||||
}
|
||||
|
||||
private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem)
|
||||
{
|
||||
ViewModel.IsAmiiboRequested = AppHost.Device.System.SearchingForAmiibo(out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
AppHost.Device.EnableDeviceVsync = !AppHost.Device.EnableDeviceVsync;
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {AppHost.Device.EnableDeviceVsync}");
|
||||
}
|
||||
|
||||
private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||
}
|
||||
|
||||
private void AspectRatioStatus_PointerReleased(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
||||
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
||||
}
|
||||
|
||||
private void VolumeStatus_CheckedChanged(object sender, SplitButtonClickEventArgs e)
|
||||
{
|
||||
var volumeSplitButton = sender as ToggleSplitButton;
|
||||
if (ViewModel.IsGameRunning)
|
||||
{
|
||||
if (!volumeSplitButton.IsChecked)
|
||||
{
|
||||
AppHost.Device.SetVolume(ConfigurationState.Instance.System.AudioVolume);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppHost.Device.SetVolume(0);
|
||||
}
|
||||
|
||||
ViewModel.Volume = AppHost.Device.GetVolume();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
if (!_isClosing && AppHost != null && ConfigurationState.Instance.ShowConfirmExit)
|
||||
{
|
||||
e.Cancel = true;
|
||||
|
||||
ConfirmExit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_isClosing = true;
|
||||
|
||||
if (AppHost != null)
|
||||
{
|
||||
AppHost.AppExit -= AppHost_AppExit;
|
||||
AppHost.AppExit += (sender, e) =>
|
||||
{
|
||||
AppHost = null;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
MainContent = null;
|
||||
|
||||
Close();
|
||||
});
|
||||
};
|
||||
AppHost?.Stop();
|
||||
|
||||
e.Cancel = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationLibrary.CancelLoading();
|
||||
InputManager.Dispose();
|
||||
Program.Exit();
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void ConfirmExit()
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
_isClosing = await ContentDialogHelper.CreateExitDialog();
|
||||
|
||||
if (_isClosing)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class MotionSettingsWindow : UserControl
|
||||
{
|
||||
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel;
|
||||
|
||||
public MotionSettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public MotionSettingsWindow(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
|
||||
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>()
|
||||
{
|
||||
Slot = config.Slot,
|
||||
AltSlot = config.AltSlot,
|
||||
DsuServerHost = config.DsuServerHost,
|
||||
DsuServerPort = config.DsuServerPort,
|
||||
MirrorInput = config.MirrorInput,
|
||||
EnableMotion = config.EnableMotion,
|
||||
Sensitivity = config.Sensitivity,
|
||||
GyroDeadzone = config.GyroDeadzone,
|
||||
EnableCemuHookMotion = config.EnableCemuHookMotion
|
||||
};
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public static async Task Show(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
MotionSettingsWindow content = new MotionSettingsWindow(viewmodel);
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["ControllerMotionTitle"],
|
||||
PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
|
||||
Content = content
|
||||
};
|
||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
config.Slot = content._viewmodel.Slot;
|
||||
config.EnableMotion = content._viewmodel.EnableMotion;
|
||||
config.Sensitivity = content._viewmodel.Sensitivity;
|
||||
config.GyroDeadzone = content._viewmodel.GyroDeadzone;
|
||||
config.AltSlot = content._viewmodel.AltSlot;
|
||||
config.DsuServerHost = content._viewmodel.DsuServerHost;
|
||||
config.DsuServerPort = content._viewmodel.DsuServerPort;
|
||||
config.EnableCemuHookMotion = content._viewmodel.EnableCemuHookMotion;
|
||||
config.MirrorInput = content._viewmodel.MirrorInput;
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class RumbleSettingsWindow : UserControl
|
||||
{
|
||||
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel;
|
||||
|
||||
public RumbleSettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public RumbleSettingsWindow(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
|
||||
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>()
|
||||
{
|
||||
StrongRumble = config.StrongRumble, WeakRumble = config.WeakRumble
|
||||
};
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public static async Task Show(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
RumbleSettingsWindow content = new RumbleSettingsWindow(viewmodel);
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["ControllerRumbleTitle"],
|
||||
PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
|
||||
Content = content,
|
||||
};
|
||||
|
||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
config.StrongRumble = content._viewmodel.StrongRumble;
|
||||
config.WeakRumble = content._viewmodel.WeakRumble;
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,980 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.SettingsWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Width="1100"
|
||||
Height="768"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="950"
|
||||
MinWidth="800"
|
||||
MinHeight="480"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<Window.Resources>
|
||||
<controls:KeyValueConverter x:Key="Key" />
|
||||
</Window.Resources>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Grid.Row="1"
|
||||
IsVisible="False"
|
||||
KeyboardNavigation.IsTabStop="False"/>
|
||||
<Grid Name="Pages" IsVisible="False" Grid.Row="2">
|
||||
<ScrollViewer Name="UiPage"
|
||||
Margin="0,0,2,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}"
|
||||
Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding CheckUpdatesOnStart}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding HideCursorOnIdle}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<ListBox
|
||||
Name="GameList"
|
||||
MinHeight="250"
|
||||
Items="{Binding GameDirectories}" />
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
Name="PathBox"
|
||||
Margin="0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}"
|
||||
VerticalAlignment="Stretch" />
|
||||
<Button
|
||||
Name="AddButton"
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirTooltip}"
|
||||
Click="AddButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveButton"
|
||||
Grid.Column="2"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}"
|
||||
Click="RemoveButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
||||
<Grid Margin="10,0,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<CheckBox IsChecked="{Binding EnableCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
||||
</CheckBox>
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Row="1"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
||||
<TextBox Margin="0,10,0,0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Text="{Binding CustomThemePath}" />
|
||||
<Button Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="10,10,0,0"
|
||||
Command="{ReflectionBinding BrowseTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
||||
Content="{locale:Locale ButtonBrowse}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Row="2"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
||||
<ComboBox VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
MinWidth="100"
|
||||
SelectedIndex="{Binding BaseStyleIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="InputPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Padding="0,0,2,0"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="4" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
||||
IsChecked="{Binding EnableDockedMode}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
||||
IsChecked="{Binding EnableKeyboard}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
||||
IsChecked="{Binding EnableMouse}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0,0,0,0" MinHeight="600" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="HotkeysPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="10,5" Orientation="Vertical" Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ShowUi, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="SystemPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemRegion}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Region}"
|
||||
ToolTip.Tip="{locale:Locale RegionTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguage}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Language}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}"
|
||||
Width="250" />
|
||||
<AutoCompleteBox
|
||||
Name="TimeZoneBox"
|
||||
Width="350"
|
||||
MaxDropDownHeight="500"
|
||||
FilterMode="Contains"
|
||||
Items="{Binding TimeZones}"
|
||||
SelectionChanged="TimeZoneBox_OnSelectionChanged"
|
||||
Text="{Binding Path=TimeZone, Mode=OneWay}"
|
||||
TextChanged="TimeZoneBox_OnTextChanged"
|
||||
ValueMemberBinding="{ReflectionBinding TzMultiBinding}"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTime}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="250"/>
|
||||
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="250,0,0,10" Orientation="Horizontal">
|
||||
<TimePicker
|
||||
VerticalAlignment="Center"
|
||||
ClockIdentifier="24HourClock"
|
||||
SelectedTime="{Binding TimeOffset}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}" />
|
||||
</StackPanel>
|
||||
<CheckBox IsChecked="{Binding EnableVsync}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}"
|
||||
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
|
||||
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" />
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemHacksNote}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding ExpandDramSize}"
|
||||
ToolTip.Tip="{locale:Locale DRamTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding IgnoreMissingServices}"
|
||||
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="CpuPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnablePptc}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}"
|
||||
ToolTip.Tip="{locale:Locale PptcToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MemoryMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="GraphicsPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackend}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendIndex}">
|
||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||
<TextBlock Text="Vulkan" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||
<TextBlock Text="OpenGL" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsPreferredGpu}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
SelectedIndex="{Binding PreferredGpuIndex}"
|
||||
Items="{Binding AvailableGpus}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTextureRecompression}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsResolutionScale}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding ResolutionScale}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ui:NumberBox
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}"
|
||||
MinWidth="150"
|
||||
SmallChange="0.1"
|
||||
LargeChange="1"
|
||||
SimpleNumberFormat="F2"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
IsVisible="{Binding IsCustomResolutionScaleActive}"
|
||||
Maximum="100"
|
||||
Minimum="0.1"
|
||||
Value="{Binding CustomResolutionScale}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MaxAnisotropy}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAspectRatio}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AspectRatio}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOff}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOn}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}"
|
||||
Width="250" />
|
||||
<TextBox Text="{Binding ShaderDumpPath}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="AudioPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioBackend}"
|
||||
ToolTip.Tip="{locale:Locale AudioBackendTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AudioBackend}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioVolume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="250" />
|
||||
<ui:NumberBox Value="{Binding Volume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="350"
|
||||
SmallChange="1"
|
||||
LargeChange="10"
|
||||
SimpleNumberFormat="F0"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Minimum="0"
|
||||
Maximum="100" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<Slider Value="{Binding Volume}"
|
||||
Margin="250,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
SmallChange="5"
|
||||
TickFrequency="5"
|
||||
IsSnapToTickEnabled="True"
|
||||
LargeChange="10"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="NetworkPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" />
|
||||
<CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}"
|
||||
ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="LoggingPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableFileLog}"
|
||||
ToolTip.Tip="{locale:Locale FileLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableStub}"
|
||||
ToolTip.Tip="{locale:Locale StubLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableInfo}"
|
||||
ToolTip.Tip="{locale:Locale InfoLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableWarn}"
|
||||
ToolTip.Tip="{locale:Locale WarnLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableError}"
|
||||
ToolTip.Tip="{locale:Locale ErrorLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTrace}"
|
||||
ToolTip.Tip="{locale:Locale TraceLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableGuest}"
|
||||
ToolTip.Tip="{locale:Locale GuestLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDebug}"
|
||||
ToolTip.Tip="{locale:Locale DebugLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsAccessLog}"
|
||||
ToolTip.Tip="{locale:Locale FileAccessLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" />
|
||||
</CheckBox>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}"
|
||||
Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}"
|
||||
Width="285" />
|
||||
<ui:NumberBox
|
||||
Maximum="3"
|
||||
Minimum="0"
|
||||
Width="150"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
SmallChange="1"
|
||||
LargeChange="1"
|
||||
Value="{Binding FsGlobalAccessLogMode}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
||||
Width="285" />
|
||||
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
||||
Width="150"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<ui:NavigationView Grid.Row="1"
|
||||
IsSettingsVisible="False"
|
||||
Name="NavPanel"
|
||||
IsBackEnabled="False"
|
||||
PaneDisplayMode="Left"
|
||||
Margin="2,10,10,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
OpenPaneLength="200">
|
||||
<ui:NavigationView.MenuItems>
|
||||
<ui:NavigationViewItem IsSelected="True"
|
||||
Content="{locale:Locale SettingsTabGeneral}"
|
||||
Tag="UiPage"
|
||||
Icon="New" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabInput}"
|
||||
Tag="InputPage"
|
||||
Icon="Games" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabHotkeys}"
|
||||
Tag="HotkeysPage"
|
||||
Icon="Keyboard" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabSystem}"
|
||||
Tag="SystemPage"
|
||||
Icon="Settings" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabCpu}"
|
||||
Tag="CpuPage">
|
||||
<ui:NavigationViewItem.Icon>
|
||||
<ui:FontIcon FontFamily="avares://Ryujinx.Ava/Assets/Fonts#Segoe Fluent Icons"
|
||||
Glyph="{controls:GlyphValueConverter Chip}" />
|
||||
</ui:NavigationViewItem.Icon>
|
||||
</ui:NavigationViewItem>
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabGraphics}"
|
||||
Tag="GraphicsPage"
|
||||
Icon="Image" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabAudio}"
|
||||
Icon="Audio"
|
||||
Tag="AudioPage" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabNetwork}"
|
||||
Tag="NetworkPage"
|
||||
Icon="Globe" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{locale:Locale SettingsTabLogging}"
|
||||
Tag="LoggingPage"
|
||||
Icon="Document" />
|
||||
</ui:NavigationView.MenuItems>
|
||||
</ui:NavigationView>
|
||||
<ReversibleStackPanel
|
||||
Grid.Row="2"
|
||||
Margin="10"
|
||||
Spacing="10"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
ReverseOrder="{ReflectionBinding IsMacOS}">
|
||||
<Button
|
||||
HotKey="Enter"
|
||||
Classes="accent"
|
||||
Content="{locale:Locale SettingsButtonOk}"
|
||||
Command="{ReflectionBinding OkButton}" />
|
||||
<Button
|
||||
HotKey="Escape"
|
||||
Content="{locale:Locale SettingsButtonCancel}"
|
||||
Command="{ReflectionBinding CancelButton}" />
|
||||
<Button
|
||||
Content="{locale:Locale SettingsButtonApply}"
|
||||
Command="{ReflectionBinding ApplyButton}" />
|
||||
</ReversibleStackPanel>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@ -1,212 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.Core;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.Assigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class SettingsWindow : StyleableWindow
|
||||
{
|
||||
private ButtonKeyAssigner _currentAssigner;
|
||||
|
||||
internal SettingsViewModel ViewModel { get; set; }
|
||||
|
||||
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
|
||||
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
|
||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
|
||||
|
||||
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
|
||||
}
|
||||
|
||||
public SettingsWindow()
|
||||
{
|
||||
ViewModel = new SettingsViewModel();
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
Pages.Children.Clear();
|
||||
NavPanel.SelectionChanged += NavPanelOnSelectionChanged;
|
||||
NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0);
|
||||
}
|
||||
|
||||
private void Button_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is ToggleButton button)
|
||||
{
|
||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentAssigner == null && (bool)button.IsChecked)
|
||||
{
|
||||
_currentAssigner = new ButtonKeyAssigner(button);
|
||||
|
||||
FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
|
||||
|
||||
PointerPressed += MouseClick;
|
||||
|
||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
||||
|
||||
_currentAssigner.GetInputAndAssign(assigner);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentAssigner != null)
|
||||
{
|
||||
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
||||
|
||||
_currentAssigner.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
button.IsChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
|
||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
bool shouldUnbind = false;
|
||||
|
||||
if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
|
||||
{
|
||||
shouldUnbind = true;
|
||||
}
|
||||
|
||||
_currentAssigner?.Cancel(shouldUnbind);
|
||||
|
||||
PointerPressed -= MouseClick;
|
||||
}
|
||||
|
||||
private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.SelectedItem is NavigationViewItem navitem)
|
||||
{
|
||||
NavPanel.Content = navitem.Tag.ToString() switch
|
||||
{
|
||||
"UiPage" => UiPage,
|
||||
"InputPage" => InputPage,
|
||||
"HotkeysPage" => HotkeysPage,
|
||||
"SystemPage" => SystemPage,
|
||||
"CpuPage" => CpuPage,
|
||||
"GraphicsPage" => GraphicsPage,
|
||||
"AudioPage" => AudioPage,
|
||||
"NetworkPage" => NetworkPage,
|
||||
"LoggingPage" => LoggingPage,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = PathBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = await new OpenFolderDialog().ShowAsync(this);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int oldIndex = GameList.SelectedIndex;
|
||||
|
||||
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||
{
|
||||
ViewModel.GameDirectories.Remove(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
|
||||
if (GameList.ItemCount > 0)
|
||||
{
|
||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.AddedItems != null && e.AddedItems.Count > 0)
|
||||
{
|
||||
if (e.AddedItems[0] is TimeZone timeZone)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is AutoCompleteBox box)
|
||||
{
|
||||
if (box.SelectedItem != null && box.SelectedItem is TimeZone timeZone)
|
||||
{
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
ControllerSettings.Dispose();
|
||||
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
<window:StyleableWindow
|
||||
x:Class="Ryujinx.Ava.Ui.Windows.TitleUpdateWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
Width="600"
|
||||
Height="400"
|
||||
MinWidth="600"
|
||||
MinHeight="400"
|
||||
MaxWidth="600"
|
||||
MaxHeight="400"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Name="Heading"
|
||||
Grid.Row="1"
|
||||
MaxWidth="500"
|
||||
Margin="20,15,20,20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
LineHeight="18"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1">
|
||||
<ScrollViewer
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Items="{Binding _titleUpdates}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<RadioButton
|
||||
Padding="8,0"
|
||||
VerticalContentAlignment="Center"
|
||||
GroupName="Update"
|
||||
IsChecked="{Binding IsEnabled, Mode=TwoWay}">
|
||||
<Label
|
||||
Margin="0"
|
||||
VerticalAlignment="Center"
|
||||
Content="{Binding Label}"
|
||||
FontSize="12" />
|
||||
</RadioButton>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<DockPanel
|
||||
Grid.Row="3"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch">
|
||||
<DockPanel Margin="0" HorizontalAlignment="Left">
|
||||
<Button
|
||||
Name="AddButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding Add}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding RemoveSelected}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding RemoveAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
<DockPanel Margin="0" HorizontalAlignment="Right">
|
||||
<Button
|
||||
Name="SaveButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding Save}">
|
||||
<TextBlock Text="{locale:Locale SettingsButtonSave}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="CancelButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding Close}">
|
||||
<TextBlock Text="{locale:Locale InputDialogCancel}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
@ -1,270 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Path = System.IO.Path;
|
||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
public partial class TitleUpdateWindow : StyleableWindow
|
||||
{
|
||||
private readonly string _titleUpdateJsonPath;
|
||||
private TitleUpdateMetadata _titleUpdateWindowData;
|
||||
|
||||
private VirtualFileSystem _virtualFileSystem { get; }
|
||||
private AvaloniaList<TitleUpdateModel> _titleUpdates { get; set; }
|
||||
|
||||
private ulong _titleId { get; }
|
||||
private string _titleName { get; }
|
||||
|
||||
public TitleUpdateWindow()
|
||||
{
|
||||
DataContext = this;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
}
|
||||
|
||||
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||
{
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
_titleUpdates = new AvaloniaList<TitleUpdateModel>();
|
||||
|
||||
_titleId = titleId;
|
||||
_titleName = titleName;
|
||||
|
||||
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
||||
|
||||
try
|
||||
{
|
||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
||||
{
|
||||
Selected = "",
|
||||
Paths = new List<string>()
|
||||
};
|
||||
}
|
||||
|
||||
DataContext = this;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
|
||||
LoadUpdates();
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
private void PrintHeading()
|
||||
{
|
||||
Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
|
||||
}
|
||||
|
||||
private void LoadUpdates()
|
||||
{
|
||||
_titleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
|
||||
|
||||
foreach (string path in _titleUpdateWindowData.Paths)
|
||||
{
|
||||
AddUpdate(path);
|
||||
}
|
||||
|
||||
if (_titleUpdateWindowData.Selected == "")
|
||||
{
|
||||
_titleUpdates[0].IsEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleUpdateModel selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
|
||||
List<TitleUpdateModel> enabled = _titleUpdates.Where(x => x.IsEnabled).ToList();
|
||||
|
||||
foreach (TitleUpdateModel update in enabled)
|
||||
{
|
||||
update.IsEnabled = false;
|
||||
}
|
||||
|
||||
if (selected != null)
|
||||
{
|
||||
selected.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
SortUpdates();
|
||||
}
|
||||
|
||||
private void AddUpdate(string path)
|
||||
{
|
||||
if (File.Exists(path) && !_titleUpdates.Any(x => x.Path == path))
|
||||
{
|
||||
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||
|
||||
try
|
||||
{
|
||||
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
|
||||
|
||||
if (controlNca != null && patchNca != null)
|
||||
{
|
||||
ApplicationControlProperty controlData = new();
|
||||
|
||||
using UniqueRef<IFile> nacpFile = new();
|
||||
|
||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||
|
||||
_titleUpdates.Add(new TitleUpdateModel(controlData, path));
|
||||
|
||||
foreach (var update in _titleUpdates)
|
||||
{
|
||||
update.IsEnabled = false;
|
||||
}
|
||||
|
||||
_titleUpdates.Last().IsEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveUpdates(bool removeSelectedOnly = false)
|
||||
{
|
||||
if (removeSelectedOnly)
|
||||
{
|
||||
_titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
_titleUpdates.RemoveAll(_titleUpdates.Where(x => !x.IsNoUpdate).ToList());
|
||||
}
|
||||
|
||||
_titleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
|
||||
|
||||
SortUpdates();
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
public void RemoveSelected()
|
||||
{
|
||||
RemoveUpdates(true);
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
RemoveUpdates();
|
||||
}
|
||||
|
||||
public async void Add()
|
||||
{
|
||||
OpenFileDialog dialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
|
||||
AllowMultiple = true
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter
|
||||
{
|
||||
Name = "NSP",
|
||||
Extensions = { "nsp" }
|
||||
});
|
||||
|
||||
string[] files = await dialog.ShowAsync(this);
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
foreach (string file in files)
|
||||
{
|
||||
AddUpdate(file);
|
||||
}
|
||||
}
|
||||
|
||||
SortUpdates();
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
private void SortUpdates()
|
||||
{
|
||||
var list = _titleUpdates.ToList();
|
||||
|
||||
list.Sort((first, second) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
||||
});
|
||||
|
||||
_titleUpdates.Clear();
|
||||
_titleUpdates.AddRange(list);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
_titleUpdateWindowData.Paths.Clear();
|
||||
|
||||
_titleUpdateWindowData.Selected = "";
|
||||
|
||||
foreach (TitleUpdateModel update in _titleUpdates)
|
||||
{
|
||||
_titleUpdateWindowData.Paths.Add(update.Path);
|
||||
|
||||
if (update.IsEnabled)
|
||||
{
|
||||
_titleUpdateWindowData.Selected = update.Path;
|
||||
}
|
||||
}
|
||||
|
||||
using (FileStream titleUpdateJsonStream = File.Create(_titleUpdateJsonPath, 4096, FileOptions.WriteThrough))
|
||||
{
|
||||
titleUpdateJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
|
||||
}
|
||||
|
||||
if (Owner is MainWindow window)
|
||||
{
|
||||
window.ViewModel.LoadApplications();
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum BackendThreading
|
||||
{
|
||||
Auto,
|
||||
Off,
|
||||
On
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum GraphicsBackend
|
||||
{
|
||||
Vulkan,
|
||||
OpenGl
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||
{
|
||||
public enum MotionInputBackendType : byte
|
||||
{
|
||||
Invalid,
|
||||
GamepadDriver,
|
||||
CemuHook
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public enum StickInputId : byte
|
||||
{
|
||||
Unbound,
|
||||
Left,
|
||||
Right,
|
||||
|
||||
Count
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public enum InputBackendType
|
||||
{
|
||||
Invalid,
|
||||
WindowKeyboard,
|
||||
GamepadSDL2,
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum MemoryManagerMode : byte
|
||||
{
|
||||
SoftwarePageTable,
|
||||
HostMapped,
|
||||
HostMappedUnsafe
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
internal class DefaultLogFormatter : ILogFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public string Format(LogEventArgs args)
|
||||
{
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
sb.Clear();
|
||||
|
||||
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
|
||||
sb.Append($" |{args.Level.ToString()[0]}| ");
|
||||
|
||||
if (args.ThreadName != null)
|
||||
{
|
||||
sb.Append(args.ThreadName);
|
||||
sb.Append(' ');
|
||||
}
|
||||
|
||||
sb.Append(args.Message);
|
||||
|
||||
if (args.Data != null)
|
||||
{
|
||||
PropertyInfo[] props = args.Data.GetType().GetProperties();
|
||||
|
||||
sb.Append(" {");
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
sb.Append(prop.Name);
|
||||
sb.Append(": ");
|
||||
|
||||
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Array array = (Array)prop.GetValue(args.Data);
|
||||
foreach (var item in array)
|
||||
{
|
||||
sb.Append(item.ToString());
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
if (array.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 2, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(prop.GetValue(args.Data));
|
||||
}
|
||||
|
||||
sb.Append(" ; ");
|
||||
}
|
||||
|
||||
// We remove the final ';' from the string
|
||||
if (props.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 3, 3);
|
||||
}
|
||||
|
||||
sb.Append('}');
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class BitUtils
|
||||
{
|
||||
public static uint AlignUp(uint value, int size)
|
||||
{
|
||||
return (uint)AlignUp((int)value, size);
|
||||
}
|
||||
|
||||
public static int AlignUp(int value, int size)
|
||||
{
|
||||
return (value + (size - 1)) & -size;
|
||||
}
|
||||
|
||||
public static ulong AlignUp(ulong value, int size)
|
||||
{
|
||||
return (ulong)AlignUp((long)value, size);
|
||||
}
|
||||
|
||||
public static long AlignUp(long value, int size)
|
||||
{
|
||||
return AlignUp(value, (long)size);
|
||||
}
|
||||
|
||||
public static ulong AlignUp(ulong value, ulong size)
|
||||
{
|
||||
return (ulong)AlignUp((long)value, (long)size);
|
||||
}
|
||||
|
||||
public static long AlignUp(long value, long size)
|
||||
{
|
||||
return (value + (size - 1)) & -size;
|
||||
}
|
||||
|
||||
public static uint AlignDown(uint value, int size)
|
||||
{
|
||||
return (uint)AlignDown((int)value, size);
|
||||
}
|
||||
|
||||
public static int AlignDown(int value, int size)
|
||||
{
|
||||
return value & -size;
|
||||
}
|
||||
|
||||
public static ulong AlignDown(ulong value, int size)
|
||||
{
|
||||
return (ulong)AlignDown((long)value, size);
|
||||
}
|
||||
|
||||
public static long AlignDown(long value, int size)
|
||||
{
|
||||
return AlignDown(value, (long)size);
|
||||
}
|
||||
|
||||
public static ulong AlignDown(ulong value, ulong size)
|
||||
{
|
||||
return (ulong)AlignDown((long)value, (long)size);
|
||||
}
|
||||
|
||||
public static long AlignDown(long value, long size)
|
||||
{
|
||||
return value & -size;
|
||||
}
|
||||
|
||||
public static int DivRoundUp(int value, int dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
}
|
||||
|
||||
public static ulong DivRoundUp(ulong value, uint dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
}
|
||||
|
||||
public static long DivRoundUp(long value, int dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
}
|
||||
|
||||
public static int Pow2RoundUp(int value)
|
||||
{
|
||||
value--;
|
||||
|
||||
value |= (value >> 1);
|
||||
value |= (value >> 2);
|
||||
value |= (value >> 4);
|
||||
value |= (value >> 8);
|
||||
value |= (value >> 16);
|
||||
|
||||
return ++value;
|
||||
}
|
||||
|
||||
public static int Pow2RoundDown(int value)
|
||||
{
|
||||
return BitOperations.IsPow2(value) ? value : Pow2RoundUp(value) >> 1;
|
||||
}
|
||||
|
||||
public static long ReverseBits64(long value)
|
||||
{
|
||||
return (long)ReverseBits64((ulong)value);
|
||||
}
|
||||
|
||||
private static ulong ReverseBits64(ulong value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
public static JsonNamingPolicy SnakeCase { get; }
|
||||
|
||||
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
||||
{
|
||||
public override string ConvertName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
char c = name[i];
|
||||
|
||||
if (char.IsUpper(c))
|
||||
{
|
||||
if (i == 0 || char.IsUpper(name[i - 1]))
|
||||
{
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("_");
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
static JsonHelper()
|
||||
{
|
||||
SnakeCase = new SnakeCaseNamingPolicy();
|
||||
}
|
||||
|
||||
public static JsonSerializerOptions GetDefaultSerializerOptions(bool prettyPrint = false)
|
||||
{
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
DictionaryKeyPolicy = SnakeCase,
|
||||
PropertyNamingPolicy = SnakeCase,
|
||||
WriteIndented = prettyPrint,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
options.Converters.Add(new JsonInputConfigConverter());
|
||||
options.Converters.Add(new JsonMotionConfigControllerConverter());
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(reader.ReadBytes((int)(stream.Length - stream.Position)), GetDefaultSerializerOptions());
|
||||
}
|
||||
}
|
||||
|
||||
public static T DeserializeFromFile<T>(string path)
|
||||
{
|
||||
return Deserialize<T>(File.ReadAllText(path));
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string json)
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(json, GetDefaultSerializerOptions());
|
||||
}
|
||||
|
||||
public static void Serialize<TValue>(Stream stream, TValue obj, bool prettyPrint = false)
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(SerializeToUtf8Bytes(obj, prettyPrint));
|
||||
}
|
||||
}
|
||||
|
||||
public static string Serialize<TValue>(TValue obj, bool prettyPrint = false)
|
||||
{
|
||||
return JsonSerializer.Serialize(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||
}
|
||||
|
||||
public static byte[] SerializeToUtf8Bytes<T>(T obj, bool prettyPrint = false)
|
||||
{
|
||||
return JsonSerializer.SerializeToUtf8Bytes(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class StreamUtils
|
||||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuMultiRegionHandle : IMultiRegionHandle
|
||||
{
|
||||
private readonly MultiRegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
|
||||
internal CpuMultiRegionHandle(MultiRegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public void ForceDirty(ulong address, ulong size) => _impl.ForceDirty(address, size);
|
||||
public IEnumerable<IRegionHandle> GetHandles() => _impl.GetHandles();
|
||||
public void QueryModified(Action<ulong, ulong> modifiedAction) => _impl.QueryModified(modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction) => _impl.QueryModified(address, size, modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber) => _impl.QueryModified(address, size, modifiedAction, sequenceNumber);
|
||||
public void RegisterAction(ulong address, ulong size, RegionSignal action) => _impl.RegisterAction(address, size, action);
|
||||
public void RegisterPreciseAction(ulong address, ulong size, PreciseRegionSignal action) => _impl.RegisterPreciseAction(address, size, action);
|
||||
public void SignalWrite() => _impl.SignalWrite();
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuRegionHandle : IRegionHandle
|
||||
{
|
||||
private readonly RegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
public bool Unmapped => _impl.Unmapped;
|
||||
public ulong Address => _impl.Address;
|
||||
public ulong Size => _impl.Size;
|
||||
public ulong EndAddress => _impl.EndAddress;
|
||||
|
||||
internal CpuRegionHandle(RegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public bool DirtyOrVolatile() => _impl.DirtyOrVolatile();
|
||||
public void ForceDirty() => _impl.ForceDirty();
|
||||
public IRegionHandle GetHandle() => _impl;
|
||||
public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
|
||||
public void RegisterPreciseAction(PreciseRegionSignal action) => _impl.RegisterPreciseAction(action);
|
||||
public void RegisterDirtyEvent(Action action) => _impl.RegisterDirtyEvent(action);
|
||||
public void Reprotect(bool asDirty = false) => _impl.Reprotect(asDirty);
|
||||
|
||||
public bool OverlapsWith(ulong address, ulong size) => _impl.OverlapsWith(address, size);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuSmartMultiRegionHandle : IMultiRegionHandle
|
||||
{
|
||||
private readonly SmartMultiRegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
|
||||
internal CpuSmartMultiRegionHandle(SmartMultiRegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public void ForceDirty(ulong address, ulong size) => _impl.ForceDirty(address, size);
|
||||
public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
|
||||
public void RegisterPreciseAction(PreciseRegionSignal action) => _impl.RegisterPreciseAction(action);
|
||||
public void QueryModified(Action<ulong, ulong> modifiedAction) => _impl.QueryModified(modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction) => _impl.QueryModified(address, size, modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber) => _impl.QueryModified(address, size, modifiedAction, sequenceNumber);
|
||||
public void SignalWrite() => _impl.SignalWrite();
|
||||
}
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Program;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Window;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
{
|
||||
static class CommandHelper
|
||||
{
|
||||
private delegate void CommandDelegate(Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer);
|
||||
|
||||
private static int _totalCommands = (int)Enum.GetValues<CommandType>().Max() + 1;
|
||||
private static CommandDelegate[] _lookup = new CommandDelegate[_totalCommands];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ref T GetCommand<T>(Span<byte> memory)
|
||||
{
|
||||
return ref Unsafe.As<byte, T>(ref MemoryMarshal.GetReference(memory));
|
||||
}
|
||||
|
||||
public static int GetMaxCommandSize()
|
||||
{
|
||||
Assembly assembly = typeof(CommandHelper).Assembly;
|
||||
|
||||
IEnumerable<Type> commands = assembly.GetTypes().Where(type => typeof(IGALCommand).IsAssignableFrom(type) && type.IsValueType);
|
||||
|
||||
int maxSize = commands.Max(command =>
|
||||
{
|
||||
MethodInfo method = typeof(Unsafe).GetMethod(nameof(Unsafe.SizeOf));
|
||||
MethodInfo generic = method.MakeGenericMethod(command);
|
||||
int size = (int)generic.Invoke(null, null);
|
||||
|
||||
return size;
|
||||
});
|
||||
|
||||
InitLookup();
|
||||
|
||||
return maxSize + 1; // 1 byte reserved for command size.
|
||||
}
|
||||
|
||||
private static void InitLookup()
|
||||
{
|
||||
_lookup[(int)CommandType.Action] = (memory, threaded, renderer) =>
|
||||
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) =>
|
||||
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) =>
|
||||
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) =>
|
||||
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) =>
|
||||
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) =>
|
||||
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) =>
|
||||
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) =>
|
||||
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) =>
|
||||
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) =>
|
||||
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) =>
|
||||
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) =>
|
||||
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) =>
|
||||
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) =>
|
||||
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) =>
|
||||
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) =>
|
||||
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) =>
|
||||
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) =>
|
||||
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) =>
|
||||
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) =>
|
||||
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) =>
|
||||
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) =>
|
||||
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) =>
|
||||
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) =>
|
||||
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) =>
|
||||
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) =>
|
||||
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) =>
|
||||
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) =>
|
||||
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) =>
|
||||
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) =>
|
||||
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) =>
|
||||
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) =>
|
||||
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
|
||||
|
||||
_lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) =>
|
||||
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) =>
|
||||
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) =>
|
||||
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) =>
|
||||
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) =>
|
||||
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) =>
|
||||
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) =>
|
||||
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) =>
|
||||
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.Draw] = (memory, threaded, renderer) =>
|
||||
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) =>
|
||||
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) =>
|
||||
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) =>
|
||||
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) =>
|
||||
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) =>
|
||||
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) =>
|
||||
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||
EndHostConditionalRenderingCommand.Run(renderer);
|
||||
_lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) =>
|
||||
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) =>
|
||||
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) =>
|
||||
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) =>
|
||||
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) =>
|
||||
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) =>
|
||||
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) =>
|
||||
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) =>
|
||||
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) =>
|
||||
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) =>
|
||||
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) =>
|
||||
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) =>
|
||||
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) =>
|
||||
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) =>
|
||||
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) =>
|
||||
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) =>
|
||||
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) =>
|
||||
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) =>
|
||||
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) =>
|
||||
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) =>
|
||||
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) =>
|
||||
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) =>
|
||||
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) =>
|
||||
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) =>
|
||||
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) =>
|
||||
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) =>
|
||||
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) =>
|
||||
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) =>
|
||||
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) =>
|
||||
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) =>
|
||||
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) =>
|
||||
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) =>
|
||||
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) =>
|
||||
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) =>
|
||||
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) =>
|
||||
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) =>
|
||||
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) =>
|
||||
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) =>
|
||||
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RunCommand(Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
_lookup[memory[memory.Length - 1]](memory, threaded, renderer);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
interface IGALCommand
|
||||
{
|
||||
CommandType CommandType { get; }
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Model
|
||||
{
|
||||
unsafe struct PinnedSpan<T> where T : unmanaged
|
||||
{
|
||||
private void* _ptr;
|
||||
private int _size;
|
||||
|
||||
public PinnedSpan(ReadOnlySpan<T> span)
|
||||
{
|
||||
_ptr = Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
|
||||
_size = span.Length;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<T> Get()
|
||||
{
|
||||
return new ReadOnlySpan<T>(_ptr, _size * Unsafe.SizeOf<T>());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public readonly struct ShaderBindings
|
||||
{
|
||||
public IReadOnlyCollection<int> UniformBufferBindings { get; }
|
||||
public IReadOnlyCollection<int> StorageBufferBindings { get; }
|
||||
public IReadOnlyCollection<int> TextureBindings { get; }
|
||||
public IReadOnlyCollection<int> ImageBindings { get; }
|
||||
|
||||
public ShaderBindings(
|
||||
IReadOnlyCollection<int> uniformBufferBindings,
|
||||
IReadOnlyCollection<int> storageBufferBindings,
|
||||
IReadOnlyCollection<int> textureBindings,
|
||||
IReadOnlyCollection<int> imageBindings)
|
||||
{
|
||||
UniformBufferBindings = uniformBufferBindings;
|
||||
StorageBufferBindings = storageBufferBindings;
|
||||
TextureBindings = textureBindings;
|
||||
ImageBindings = imageBindings;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
/// <summary>
|
||||
/// A texture cache that automatically removes older textures that are not used for some time.
|
||||
/// The cache works with a rotated list with a fixed size. When new textures are added, the
|
||||
/// old ones at the bottom of the list are deleted.
|
||||
/// </summary>
|
||||
class AutoDeleteCache : IEnumerable<Texture>
|
||||
{
|
||||
private const int MaxCapacity = 2048;
|
||||
|
||||
private readonly LinkedList<Texture> _textures;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the automatic deletion cache.
|
||||
/// </summary>
|
||||
public AutoDeleteCache()
|
||||
{
|
||||
_textures = new LinkedList<Texture>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new texture to the cache, even if the texture added is already on the cache.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using this method is only recommended if you know that the texture is not yet on the cache,
|
||||
/// otherwise it would store the same texture more than once.
|
||||
/// </remarks>
|
||||
/// <param name="texture">The texture to be added to the cache</param>
|
||||
public void Add(Texture texture)
|
||||
{
|
||||
texture.IncrementReferenceCount();
|
||||
|
||||
texture.CacheNode = _textures.AddLast(texture);
|
||||
|
||||
if (_textures.Count > MaxCapacity)
|
||||
{
|
||||
Texture oldestTexture = _textures.First.Value;
|
||||
|
||||
if (!oldestTexture.CheckModified(false))
|
||||
{
|
||||
// The texture must be flushed if it falls out of the auto delete cache.
|
||||
// Flushes out of the auto delete cache do not trigger write tracking,
|
||||
// as it is expected that other overlapping textures exist that have more up-to-date contents.
|
||||
|
||||
oldestTexture.Group.SynchronizeDependents(oldestTexture);
|
||||
oldestTexture.FlushModified(false);
|
||||
}
|
||||
|
||||
_textures.RemoveFirst();
|
||||
|
||||
oldestTexture.DecrementReferenceCount();
|
||||
|
||||
oldestTexture.CacheNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new texture to the cache, or just moves it to the top of the list if the
|
||||
/// texture is already on the cache.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Moving the texture to the top of the list prevents it from being deleted,
|
||||
/// as the textures on the bottom of the list are deleted when new ones are added.
|
||||
/// </remarks>
|
||||
/// <param name="texture">The texture to be added, or moved to the top</param>
|
||||
public void Lift(Texture texture)
|
||||
{
|
||||
if (texture.CacheNode != null)
|
||||
{
|
||||
if (texture.CacheNode != _textures.Last)
|
||||
{
|
||||
_textures.Remove(texture.CacheNode);
|
||||
|
||||
texture.CacheNode = _textures.AddLast(texture);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(Texture texture, bool flush)
|
||||
{
|
||||
if (texture.CacheNode == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove our reference to this texture.
|
||||
if (flush)
|
||||
{
|
||||
texture.FlushModified(false);
|
||||
}
|
||||
|
||||
_textures.Remove(texture.CacheNode);
|
||||
|
||||
texture.CacheNode = null;
|
||||
|
||||
return texture.DecrementReferenceCount();
|
||||
}
|
||||
|
||||
public IEnumerator<Texture> GetEnumerator()
|
||||
{
|
||||
return _textures.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _textures.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
public class UnmapEventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
public UnmapEventArgs(ulong address, ulong size)
|
||||
{
|
||||
Address = address;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
public readonly struct FrameDecodedEventArgs
|
||||
{
|
||||
public CodecId CodecId { get; }
|
||||
public uint LumaOffset { get; }
|
||||
public uint ChromaOffset { get; }
|
||||
|
||||
internal FrameDecodedEventArgs(CodecId codecId, uint lumaOffset, uint chromaOffset)
|
||||
{
|
||||
CodecId = codecId;
|
||||
LumaOffset = lumaOffset;
|
||||
ChromaOffset = chromaOffset;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
// Note: Most of those names are not official.
|
||||
struct NvdecRegisters
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Array64<uint> Reserved0;
|
||||
public Array64<uint> Reserved100;
|
||||
public uint SetCodecID;
|
||||
public Array63<uint> Reserved204;
|
||||
public uint Execute;
|
||||
public Array63<uint> Reserved304;
|
||||
public uint SetPlatformID;
|
||||
public uint SetPictureInfoOffset;
|
||||
public uint SetBitstreamOffset;
|
||||
public uint SetFrameNumber;
|
||||
public uint SetH264SliceDataOffsetsOffset; // Also used by VC1
|
||||
public uint SetH264MvDumpOffset; // Also used by VC1
|
||||
public uint Unknown418; // Used by VC1
|
||||
public uint Unknown41C;
|
||||
public uint Unknown420; // Used by VC1
|
||||
public uint SetFrameStatsOffset;
|
||||
public uint SetH264LastSurfaceLumaOffset;
|
||||
public uint SetH264LastSurfaceChromaOffset;
|
||||
public Array17<uint> SetSurfaceLumaOffset;
|
||||
public Array17<uint> SetSurfaceChromaOffset;
|
||||
public uint Unknown4B8;
|
||||
public uint Unknown4BC;
|
||||
public uint SetCryptoData0Offset;
|
||||
public uint SetCryptoData1Offset;
|
||||
public Array62<uint> Unknown4C8;
|
||||
public uint SetVp9EntropyProbsOffset;
|
||||
public uint SetVp9BackwardUpdatesOffset;
|
||||
public uint SetVp9LastFrameSegMapOffset;
|
||||
public uint SetVp9CurrFrameSegMapOffset;
|
||||
public uint Unknown5D0;
|
||||
public uint SetVp9LastFrameMvsOffset;
|
||||
public uint SetVp9CurrFrameMvsOffset;
|
||||
public uint Unknown5DC;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.Graphics" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,214 +0,0 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL.Image;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
class Window : IWindow, IDisposable
|
||||
{
|
||||
private const int TextureCount = 3;
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
private int _width;
|
||||
private int _height;
|
||||
private int _copyFramebufferHandle;
|
||||
|
||||
internal BackgroundContextWorker BackgroundContext { get; private set; }
|
||||
|
||||
internal bool ScreenCaptureRequested { get; set; }
|
||||
|
||||
public Window(OpenGLRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
|
||||
{
|
||||
GL.Disable(EnableCap.FramebufferSrgb);
|
||||
|
||||
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
|
||||
|
||||
CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop, swapBuffersCallback);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
|
||||
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
|
||||
// Restore unpack alignment to 4, as performance overlays such as RTSS may change this to load their resources.
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
|
||||
}
|
||||
|
||||
public void ChangeVSyncMode(bool vsyncEnabled) { }
|
||||
|
||||
public void SetSize(int width, int height)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop, Action swapBuffersCallback)
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
|
||||
|
||||
TextureView viewConverted = view.Format.IsBgr() ? _renderer.TextureCopy.BgraSwap(view) : view;
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.ReadFramebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
viewConverted.Handle,
|
||||
0);
|
||||
|
||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||
|
||||
GL.Disable(EnableCap.RasterizerDiscard);
|
||||
GL.Disable(IndexedEnableCap.ScissorTest, 0);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
int srcX0, srcX1, srcY0, srcY1;
|
||||
float scale = view.ScaleFactor;
|
||||
|
||||
if (crop.Left == 0 && crop.Right == 0)
|
||||
{
|
||||
srcX0 = 0;
|
||||
srcX1 = (int)(view.Width / scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
srcX0 = crop.Left;
|
||||
srcX1 = crop.Right;
|
||||
}
|
||||
|
||||
if (crop.Top == 0 && crop.Bottom == 0)
|
||||
{
|
||||
srcY0 = 0;
|
||||
srcY1 = (int)(view.Height / scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
srcY0 = crop.Top;
|
||||
srcY1 = crop.Bottom;
|
||||
}
|
||||
|
||||
if (scale != 1f)
|
||||
{
|
||||
srcX0 = (int)(srcX0 * scale);
|
||||
srcY0 = (int)(srcY0 * scale);
|
||||
srcX1 = (int)Math.Ceiling(srcX1 * scale);
|
||||
srcY1 = (int)Math.Ceiling(srcY1 * scale);
|
||||
}
|
||||
|
||||
float ratioX = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _height * crop.AspectRatioX / (_width * crop.AspectRatioY));
|
||||
float ratioY = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _width * crop.AspectRatioY / (_height * crop.AspectRatioX));
|
||||
|
||||
int dstWidth = (int)(_width * ratioX);
|
||||
int dstHeight = (int)(_height * ratioY);
|
||||
|
||||
int dstPaddingX = (_width - dstWidth) / 2;
|
||||
int dstPaddingY = (_height - dstHeight) / 2;
|
||||
|
||||
int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
|
||||
int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;
|
||||
|
||||
int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
|
||||
int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;
|
||||
|
||||
if (ScreenCaptureRequested)
|
||||
{
|
||||
CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr(), crop.FlipX, crop.FlipY);
|
||||
|
||||
ScreenCaptureRequested = false;
|
||||
}
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
srcX0,
|
||||
srcY0,
|
||||
srcX1,
|
||||
srcY1,
|
||||
dstX0,
|
||||
dstY0,
|
||||
dstX1,
|
||||
dstY1,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
|
||||
// Remove Alpha channel
|
||||
GL.ColorMask(false, false, false, true);
|
||||
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
||||
{
|
||||
((Pipeline)_renderer.Pipeline).RestoreComponentMask(i);
|
||||
}
|
||||
|
||||
// Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture.
|
||||
GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne);
|
||||
GL.Viewport(0, 0, _width, _height);
|
||||
|
||||
swapBuffersCallback();
|
||||
|
||||
((Pipeline)_renderer.Pipeline).RestoreClipControl();
|
||||
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
||||
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
||||
((Pipeline)_renderer.Pipeline).RestoreViewport0();
|
||||
|
||||
if (viewConverted != view)
|
||||
{
|
||||
viewConverted.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetCopyFramebufferHandleLazy()
|
||||
{
|
||||
int handle = _copyFramebufferHandle;
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
handle = GL.GenFramebuffer();
|
||||
|
||||
_copyFramebufferHandle = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
||||
{
|
||||
BackgroundContext = new BackgroundContextWorker(baseContext);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void CaptureFrame(int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY)
|
||||
{
|
||||
long size = Math.Abs(4 * width * height);
|
||||
byte[] bitmap = new byte[size];
|
||||
|
||||
GL.ReadPixels(x, y, width, height, isBgra ? PixelFormat.Bgra : PixelFormat.Rgba, PixelType.UnsignedByte, bitmap);
|
||||
|
||||
_renderer.OnScreenCaptured(new ScreenCaptureImageInfo(width, height, isBgra, bitmap, flipX, flipY));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackgroundContext.Dispose();
|
||||
|
||||
if (_copyFramebufferHandle != 0)
|
||||
{
|
||||
GL.DeleteFramebuffer(_copyFramebufferHandle);
|
||||
|
||||
_copyFramebufferHandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return inputVec;
|
||||
}
|
||||
return ivec2(vec2(inputVec) * scale);
|
||||
}
|
||||
|
||||
int Helper_TextureSizeUnscale(int size, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return int(float(size) / scale);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[1 + samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return inputVec;
|
||||
}
|
||||
if (scale < 0.0) // If less than 0, try interpolate between texels by using the screen position.
|
||||
{
|
||||
return ivec2(vec2(inputVec) * (-scale) + mod(gl_FragCoord.xy, 0.0 - scale));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ivec2(vec2(inputVec) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
int Helper_TextureSizeUnscale(int size, int samplerIndex)
|
||||
{
|
||||
float scale = abs(s_render_scale[1 + samplerIndex]);
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return int(float(size) / scale);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user