Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
33f544fd92 | ||
|
b423197619 | ||
|
8edfb2bc7b | ||
|
ddefb4fff4 | ||
|
2efd74b9cb | ||
|
8c61ddd49d | ||
|
7b2225c6b0 | ||
|
fe15c77d30 | ||
|
5e9678c8fa | ||
|
773e239db7 | ||
|
42750a74f8 | ||
|
3ab0a71c7b | ||
|
6e784e0aca | ||
|
5a0aa074b6 | ||
|
93aa40f1fb | ||
|
bedee64af5 | ||
|
86931cc3f1 | ||
|
2be8b6ea45 | ||
|
f95b7c5877 | ||
|
eb528ae0f0 | ||
|
487261592e | ||
|
9e04e6cba1 | ||
|
4cf2419e6c | ||
|
440abac9f8 | ||
|
732714349e | ||
|
016262514d | ||
|
326749498b | ||
|
fec8291c17 | ||
|
c5d9e67cb2 | ||
|
e5261228d7 | ||
|
e61c09bc85 | ||
|
ac2444f908 | ||
|
9c6071a645 | ||
|
fa32ef9275 | ||
|
7805d27e67 | ||
|
6c515e1822 | ||
|
8a363b5df2 | ||
|
2b5abac809 | ||
|
c19c8bbade | ||
|
1c7a90ef35 | ||
|
3b46bb73f7 |
@@ -1,8 +1,7 @@
|
|||||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
# C# files
|
[*]
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
#### Core EditorConfig Options ####
|
#### Core EditorConfig Options ####
|
||||||
|
|
||||||
@@ -12,8 +11,18 @@ indent_style = space
|
|||||||
tab_width = 4
|
tab_width = 4
|
||||||
|
|
||||||
# New line preferences
|
# New line preferences
|
||||||
end_of_line = crlf
|
end_of_line = lf
|
||||||
insert_final_newline = false
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# JSON files
|
||||||
|
[*.json]
|
||||||
|
|
||||||
|
# Indentation and spacing
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
|
||||||
|
# C# files
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
#### .NET Coding Conventions ####
|
||||||
|
|
||||||
@@ -59,7 +68,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion
|
|||||||
dotnet_style_readonly_field = true:suggestion
|
dotnet_style_readonly_field = true:suggestion
|
||||||
|
|
||||||
# Parameter preferences
|
# Parameter preferences
|
||||||
dotnet_code_quality_unused_parameters = all:suggestion
|
dotnet_code_quality_unused_parameters = all:silent
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
#### C# Coding Conventions ####
|
||||||
|
|
||||||
@@ -85,7 +94,7 @@ csharp_style_expression_bodied_properties = true:silent
|
|||||||
# Pattern matching preferences
|
# Pattern matching preferences
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||||
csharp_style_prefer_switch_expression = true:suggestion
|
csharp_style_prefer_switch_expression = false:silent
|
||||||
|
|
||||||
# Null-checking preferences
|
# Null-checking preferences
|
||||||
csharp_style_conditional_delegate_call = true:suggestion
|
csharp_style_conditional_delegate_call = true:suggestion
|
||||||
@@ -94,6 +103,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
|||||||
csharp_prefer_static_local_function = true:suggestion
|
csharp_prefer_static_local_function = true:suggestion
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||||
csharp_style_prefer_readonly_struct = true
|
csharp_style_prefer_readonly_struct = true
|
||||||
|
csharp_style_prefer_method_group_conversion = true
|
||||||
|
|
||||||
# Code-block preferences
|
# Code-block preferences
|
||||||
csharp_prefer_braces = true:silent
|
csharp_prefer_braces = true:silent
|
||||||
@@ -109,6 +119,7 @@ csharp_style_prefer_range_operator = true:suggestion
|
|||||||
csharp_style_throw_expression = true:suggestion
|
csharp_style_throw_expression = true:suggestion
|
||||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||||
|
|
||||||
# 'using' directive preferences
|
# 'using' directive preferences
|
||||||
csharp_using_directive_placement = outside_namespace:silent
|
csharp_using_directive_placement = outside_namespace:silent
|
||||||
@@ -140,7 +151,6 @@ csharp_space_after_dot = false
|
|||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
csharp_space_around_binary_operators = before_and_after
|
csharp_space_around_binary_operators = before_and_after
|
||||||
csharp_space_around_declaration_statements = false
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
csharp_space_before_comma = false
|
csharp_space_before_comma = false
|
||||||
csharp_space_before_dot = false
|
csharp_space_before_dot = false
|
||||||
@@ -158,23 +168,31 @@ csharp_space_between_square_brackets = false
|
|||||||
|
|
||||||
# Wrapping preferences
|
# Wrapping preferences
|
||||||
csharp_preserve_single_line_blocks = true
|
csharp_preserve_single_line_blocks = true
|
||||||
csharp_preserve_single_line_statements = true
|
csharp_preserve_single_line_statements = false
|
||||||
|
|
||||||
#### Naming styles ####
|
#### Naming styles ####
|
||||||
|
|
||||||
# Naming rules
|
# Naming rules
|
||||||
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.severity = suggestion
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.symbols = interface
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.style = IPascalCase
|
||||||
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
dotnet_naming_rule.types_should_be_pascal_case.style = PascalCase
|
||||||
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = PascalCase
|
||||||
|
|
||||||
|
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.symbols = private_static_readonly_fields
|
||||||
|
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.severity = suggestion
|
||||||
|
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.style = _camelCase
|
||||||
|
|
||||||
|
dotnet_naming_rule.local_constants_should_be_pascal_case.symbols = local_constants
|
||||||
|
dotnet_naming_rule.local_constants_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.local_constants_should_be_pascal_case.style = PascalCase
|
||||||
|
|
||||||
# Symbol specifications
|
# Symbol specifications
|
||||||
|
|
||||||
@@ -190,14 +208,39 @@ dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, meth
|
|||||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
|
||||||
|
dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private
|
||||||
|
dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = static, readonly
|
||||||
|
|
||||||
|
dotnet_naming_symbols.local_constants.applicable_kinds = local
|
||||||
|
dotnet_naming_symbols.local_constants.applicable_accessibilities = local
|
||||||
|
dotnet_naming_symbols.local_constants.required_modifiers = const
|
||||||
|
|
||||||
# Naming styles
|
# Naming styles
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case.required_prefix =
|
dotnet_naming_style._camelCase.required_prefix = _
|
||||||
dotnet_naming_style.pascal_case.required_suffix =
|
dotnet_naming_style._camelCase.required_suffix =
|
||||||
dotnet_naming_style.pascal_case.word_separator =
|
dotnet_naming_style._camelCase.word_separator =
|
||||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
dotnet_naming_style._camelCase.capitalization = camel_case
|
||||||
|
|
||||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
dotnet_naming_style.PascalCase.required_prefix =
|
||||||
dotnet_naming_style.begins_with_i.required_suffix =
|
dotnet_naming_style.PascalCase.required_suffix =
|
||||||
dotnet_naming_style.begins_with_i.word_separator =
|
dotnet_naming_style.PascalCase.word_separator =
|
||||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
dotnet_naming_style.PascalCase.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.IPascalCase.required_prefix = I
|
||||||
|
dotnet_naming_style.IPascalCase.required_suffix =
|
||||||
|
dotnet_naming_style.IPascalCase.word_separator =
|
||||||
|
dotnet_naming_style.IPascalCase.capitalization = pascal_case
|
||||||
|
|
||||||
|
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
||||||
|
# Disable "mark members as static" rule for services
|
||||||
|
dotnet_diagnostic.CA1822.severity = none
|
||||||
|
|
||||||
|
[src/Ryujinx.Ava/UI/ViewModels/**.cs]
|
||||||
|
# Disable "mark members as static" rule for ViewModels
|
||||||
|
dotnet_diagnostic.CA1822.severity = none
|
||||||
|
|
||||||
|
[src/Ryujinx.Tests/Cpu/*.cs]
|
||||||
|
# Disable naming rules for CPU tests
|
||||||
|
dotnet_diagnostic.IDE1006.severity = none
|
||||||
|
8
.github/assign/audio.yml
vendored
8
.github/assign/audio.yml
vendored
@@ -1,8 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- marysaka
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- audio
|
|
11
.github/assign/cpu.yml
vendored
11
.github/assign/cpu.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- gdkchan
|
|
||||||
- riperiperi
|
|
||||||
- marysaka
|
|
||||||
- LDj3SNuD
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- cpu
|
|
4
.github/assign/global.yml
vendored
4
.github/assign/global.yml
vendored
@@ -1,4 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- Ryujinx/developers
|
|
10
.github/assign/gpu.yml
vendored
10
.github/assign/gpu.yml
vendored
@@ -1,10 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- gdkchan
|
|
||||||
- riperiperi
|
|
||||||
- marysaka
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- gpu
|
|
11
.github/assign/gui.yml
vendored
11
.github/assign/gui.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- Ack77
|
|
||||||
- emmauss
|
|
||||||
- TSRBerry
|
|
||||||
- marysaka
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- gui
|
|
11
.github/assign/horizon.yml
vendored
11
.github/assign/horizon.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- gdkchan
|
|
||||||
- Ack77
|
|
||||||
- marysaka
|
|
||||||
- TSRBerry
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- horizon
|
|
9
.github/assign/infra.yml
vendored
9
.github/assign/infra.yml
vendored
@@ -1,9 +0,0 @@
|
|||||||
addReviewers: true
|
|
||||||
|
|
||||||
reviewers:
|
|
||||||
- marysaka
|
|
||||||
- TSRBerry
|
|
||||||
|
|
||||||
filterLabels:
|
|
||||||
include:
|
|
||||||
- infra
|
|
32
.github/reviewers.yml
vendored
Normal file
32
.github/reviewers.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
audio:
|
||||||
|
- marysaka
|
||||||
|
|
||||||
|
cpu:
|
||||||
|
- gdkchan
|
||||||
|
- riperiperi
|
||||||
|
- marysaka
|
||||||
|
- LDj3SNuD
|
||||||
|
|
||||||
|
gpu:
|
||||||
|
- gdkchan
|
||||||
|
- riperiperi
|
||||||
|
- marysaka
|
||||||
|
|
||||||
|
gui:
|
||||||
|
- Ack77
|
||||||
|
- emmauss
|
||||||
|
- TSRBerry
|
||||||
|
- marysaka
|
||||||
|
|
||||||
|
horizon:
|
||||||
|
- gdkchan
|
||||||
|
- Ack77
|
||||||
|
- marysaka
|
||||||
|
- TSRBerry
|
||||||
|
|
||||||
|
infra:
|
||||||
|
- marysaka
|
||||||
|
- TSRBerry
|
||||||
|
|
||||||
|
default:
|
||||||
|
- marysaka
|
79
.github/update_reviewers.py
vendored
Normal file
79
.github/update_reviewers.py
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Set
|
||||||
|
from github import Github
|
||||||
|
from github.Repository import Repository
|
||||||
|
from github.GithubException import GithubException
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def add_reviewers(
|
||||||
|
reviewers: Set[str], team_reviewers: Set[str], new_entries: List[str]
|
||||||
|
):
|
||||||
|
for reviewer in new_entries:
|
||||||
|
if reviewer.startswith("@"):
|
||||||
|
team_reviewers.add(reviewer[1:])
|
||||||
|
else:
|
||||||
|
reviewers.add(reviewer)
|
||||||
|
|
||||||
|
|
||||||
|
def update_reviewers(config, repo: Repository, pr_id: int) -> int:
|
||||||
|
pull_request = repo.get_pull(pr_id)
|
||||||
|
|
||||||
|
if not pull_request:
|
||||||
|
sys.stderr.writable(f"Unknown PR #{pr_id}\n")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
pull_request_author = pull_request.user.login
|
||||||
|
reviewers = set()
|
||||||
|
team_reviewers = set()
|
||||||
|
|
||||||
|
for label in pull_request.labels:
|
||||||
|
if label.name in config:
|
||||||
|
add_reviewers(reviewers, team_reviewers, config[label.name])
|
||||||
|
|
||||||
|
if "default" in config:
|
||||||
|
add_reviewers(reviewers, team_reviewers, config["default"])
|
||||||
|
|
||||||
|
if pull_request_author in reviewers:
|
||||||
|
reviewers.remove(pull_request_author)
|
||||||
|
|
||||||
|
try:
|
||||||
|
reviewers = list(reviewers)
|
||||||
|
team_reviewers = list(team_reviewers)
|
||||||
|
print(
|
||||||
|
f"Attempting to assign reviewers ({reviewers}) and team_reviewers ({team_reviewers})"
|
||||||
|
)
|
||||||
|
pull_request.create_review_request(reviewers, team_reviewers)
|
||||||
|
return 0
|
||||||
|
except GithubException as e:
|
||||||
|
sys.stderr.write(f"Cannot assign review request for PR #{pr_id}: {e}\n")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 5:
|
||||||
|
sys.stderr.write("usage: <token> <repo_path> <pr_id> <config_path>\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
token = sys.argv[1]
|
||||||
|
repo_path = sys.argv[2]
|
||||||
|
pr_id = int(sys.argv[3])
|
||||||
|
config_path = Path(sys.argv[4])
|
||||||
|
|
||||||
|
g = Github(token)
|
||||||
|
repo = g.get_repo(repo_path)
|
||||||
|
|
||||||
|
if not repo:
|
||||||
|
sys.stderr.write("Repository not found!\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not config_path.exists():
|
||||||
|
sys.stderr.write(f'Config "{config_path}" not found!\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(config_path, "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
sys.exit(update_reviewers(config, repo, pr_id))
|
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -1,20 +1,7 @@
|
|||||||
name: Build job
|
name: Build job
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_call:
|
||||||
inputs: {}
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
paths-ignore:
|
|
||||||
- '.github/**'
|
|
||||||
- '*.yml'
|
|
||||||
- '*.json'
|
|
||||||
- '*.config'
|
|
||||||
- 'README.md'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: pr-checks-${{ github.event.number }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
@@ -63,7 +50,11 @@ jobs:
|
|||||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
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
|
- name: Test
|
||||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
uses: TSRBerry/unstable-commands@v1
|
||||||
|
with:
|
||||||
|
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||||
|
timeout-minutes: 10
|
||||||
|
retry-codes: 139
|
||||||
|
|
||||||
- name: Publish Ryujinx
|
- 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 src/Ryujinx --self-contained true
|
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
|
||||||
|
71
.github/workflows/checks.yml
vendored
Normal file
71
.github/workflows/checks.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
name: Perform checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
paths:
|
||||||
|
- '**'
|
||||||
|
- '!.github/**'
|
||||||
|
- '!*.yml'
|
||||||
|
- '!*.config'
|
||||||
|
- '!README.md'
|
||||||
|
- '.github/workflows/*.yml'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: pr-checks-${{ github.event.number }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
global-json-file: global.json
|
||||||
|
|
||||||
|
- run: dotnet restore
|
||||||
|
|
||||||
|
- name: Print dotnet format version
|
||||||
|
run: dotnet format --version
|
||||||
|
|
||||||
|
- name: Run dotnet format whitespace
|
||||||
|
run: |
|
||||||
|
dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d
|
||||||
|
|
||||||
|
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||||
|
# so in that case we'll try again (3 tries max).
|
||||||
|
- name: Run dotnet format style
|
||||||
|
uses: TSRBerry/unstable-commands@v1
|
||||||
|
with:
|
||||||
|
commands: dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
|
||||||
|
timeout-minutes: 5
|
||||||
|
retry-codes: 139
|
||||||
|
|
||||||
|
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||||
|
# so in that case we'll try again (3 tries max).
|
||||||
|
- name: Run dotnet format analyzers
|
||||||
|
uses: TSRBerry/unstable-commands@v1
|
||||||
|
with:
|
||||||
|
commands: dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d
|
||||||
|
timeout-minutes: 5
|
||||||
|
retry-codes: 139
|
||||||
|
|
||||||
|
- name: Upload report
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dotnet-format
|
||||||
|
path: ./*-report.json
|
||||||
|
|
||||||
|
pr_build:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
needs: format
|
||||||
|
secrets: inherit
|
4
.github/workflows/nightly_pr_comment.yml
vendored
4
.github/workflows/nightly_pr_comment.yml
vendored
@@ -1,8 +1,10 @@
|
|||||||
name: Comment PR artifacts links
|
name: Comment PR artifacts links
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ['Build job']
|
workflows: ['Perform checks']
|
||||||
types: [completed]
|
types: [completed]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pr_comment:
|
pr_comment:
|
||||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
|
49
.github/workflows/pr_triage.yml
vendored
49
.github/workflows/pr_triage.yml
vendored
@@ -12,43 +12,24 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# Grab sources to get update_reviewers.py and reviewers.yml
|
||||||
|
- name: Fetch sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||||
|
fetch-depth: 0
|
||||||
|
repository: Ryujinx/Ryujinx
|
||||||
|
ref: master
|
||||||
|
|
||||||
- name: Update labels based on changes
|
- name: Update labels based on changes
|
||||||
uses: actions/labeler@v4
|
uses: actions/labeler@v4
|
||||||
with:
|
with:
|
||||||
sync-labels: true
|
sync-labels: true
|
||||||
dot: true
|
dot: true
|
||||||
|
|
||||||
- name: Auto Assign [Audio]
|
- name: Assign reviewers
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
if: ! github.event.pull_request.draft
|
||||||
with:
|
run: |
|
||||||
configuration-path: '.github/assign/audio.yml'
|
pip3 install PyGithub
|
||||||
|
python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||||
- name: Auto Assign [CPU]
|
shell: bash
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/cpu.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [GPU]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/gpu.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [GUI]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/gui.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Horizon]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/horizon.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Infra]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/infra.yml'
|
|
||||||
|
|
||||||
- name: Auto Assign [Global]
|
|
||||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
|
||||||
with:
|
|
||||||
configuration-path: '.github/assign/global.yml'
|
|
||||||
|
@@ -3,24 +3,24 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia" Version="0.10.21" />
|
<PackageVersion Include="Avalonia" Version="11.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.21" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.21" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.21" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.21" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.3" />
|
||||||
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
|
<PackageVersion Include="Avalonia.Svg" Version="11.0.0" />
|
||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.1" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||||
<PackageVersion Include="LibHac" Version="0.18.0" />
|
<PackageVersion Include="LibHac" Version="0.18.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
<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.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
@@ -48,6 +48,5 @@
|
|||||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@@ -44,9 +44,114 @@
|
|||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>11.0</string>
|
<string>11.0</string>
|
||||||
|
<key>UTExportedTypeDeclarations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Extensible Application Markup Language</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.xml</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.xaml</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>xaml</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Nintendo Submission Package</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.nsp</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>nsp</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Nintendo Switch Cartridge</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.xci</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>xci</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Nintendo Content Archive</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.nca</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>nca</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Nintendo Relocatable Object</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.nro</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>nro</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Nintendo Shared Object</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.ryujinx.nso</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>nso</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>LSEnvironment</key>
|
<key>LSEnvironment</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>COMPlus_DefaultStackSize</key>
|
<key>DOTNET_DefaultStackSize</key>
|
||||||
<string>200000</string>
|
<string>200000</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
@@ -330,6 +330,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("011111100x110000110010xxxxxxxxxx", InstName.Fmaxnmp_S, InstEmit.Fmaxnmp_S, OpCodeSimd.Create);
|
SetA64("011111100x110000110010xxxxxxxxxx", InstName.Fmaxnmp_S, InstEmit.Fmaxnmp_S, OpCodeSimd.Create);
|
||||||
SetA64("0>1011100<1xxxxx110001xxxxxxxxxx", InstName.Fmaxnmp_V, InstEmit.Fmaxnmp_V, OpCodeSimdReg.Create);
|
SetA64("0>1011100<1xxxxx110001xxxxxxxxxx", InstName.Fmaxnmp_V, InstEmit.Fmaxnmp_V, OpCodeSimdReg.Create);
|
||||||
SetA64("0110111000110000110010xxxxxxxxxx", InstName.Fmaxnmv_V, InstEmit.Fmaxnmv_V, OpCodeSimd.Create);
|
SetA64("0110111000110000110010xxxxxxxxxx", InstName.Fmaxnmv_V, InstEmit.Fmaxnmv_V, OpCodeSimd.Create);
|
||||||
|
SetA64("011111100x110000111110xxxxxxxxxx", InstName.Fmaxp_S, InstEmit.Fmaxp_S, OpCodeSimd.Create);
|
||||||
SetA64("0>1011100<1xxxxx111101xxxxxxxxxx", InstName.Fmaxp_V, InstEmit.Fmaxp_V, OpCodeSimdReg.Create);
|
SetA64("0>1011100<1xxxxx111101xxxxxxxxxx", InstName.Fmaxp_V, InstEmit.Fmaxp_V, OpCodeSimdReg.Create);
|
||||||
SetA64("0110111000110000111110xxxxxxxxxx", InstName.Fmaxv_V, InstEmit.Fmaxv_V, OpCodeSimd.Create);
|
SetA64("0110111000110000111110xxxxxxxxxx", InstName.Fmaxv_V, InstEmit.Fmaxv_V, OpCodeSimd.Create);
|
||||||
SetA64("000111100x1xxxxx010110xxxxxxxxxx", InstName.Fmin_S, InstEmit.Fmin_S, OpCodeSimdReg.Create);
|
SetA64("000111100x1xxxxx010110xxxxxxxxxx", InstName.Fmin_S, InstEmit.Fmin_S, OpCodeSimdReg.Create);
|
||||||
@@ -339,6 +340,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("011111101x110000110010xxxxxxxxxx", InstName.Fminnmp_S, InstEmit.Fminnmp_S, OpCodeSimd.Create);
|
SetA64("011111101x110000110010xxxxxxxxxx", InstName.Fminnmp_S, InstEmit.Fminnmp_S, OpCodeSimd.Create);
|
||||||
SetA64("0>1011101<1xxxxx110001xxxxxxxxxx", InstName.Fminnmp_V, InstEmit.Fminnmp_V, OpCodeSimdReg.Create);
|
SetA64("0>1011101<1xxxxx110001xxxxxxxxxx", InstName.Fminnmp_V, InstEmit.Fminnmp_V, OpCodeSimdReg.Create);
|
||||||
SetA64("0110111010110000110010xxxxxxxxxx", InstName.Fminnmv_V, InstEmit.Fminnmv_V, OpCodeSimd.Create);
|
SetA64("0110111010110000110010xxxxxxxxxx", InstName.Fminnmv_V, InstEmit.Fminnmv_V, OpCodeSimd.Create);
|
||||||
|
SetA64("011111101x110000111110xxxxxxxxxx", InstName.Fminp_S, InstEmit.Fminp_S, OpCodeSimd.Create);
|
||||||
SetA64("0>1011101<1xxxxx111101xxxxxxxxxx", InstName.Fminp_V, InstEmit.Fminp_V, OpCodeSimdReg.Create);
|
SetA64("0>1011101<1xxxxx111101xxxxxxxxxx", InstName.Fminp_V, InstEmit.Fminp_V, OpCodeSimdReg.Create);
|
||||||
SetA64("0110111010110000111110xxxxxxxxxx", InstName.Fminv_V, InstEmit.Fminv_V, OpCodeSimd.Create);
|
SetA64("0110111010110000111110xxxxxxxxxx", InstName.Fminv_V, InstEmit.Fminv_V, OpCodeSimd.Create);
|
||||||
SetA64("010111111xxxxxxx0001x0xxxxxxxxxx", InstName.Fmla_Se, InstEmit.Fmla_Se, OpCodeSimdRegElemF.Create);
|
SetA64("010111111xxxxxxx0001x0xxxxxxxxxx", InstName.Fmla_Se, InstEmit.Fmla_Se, OpCodeSimdRegElemF.Create);
|
||||||
|
@@ -883,6 +883,31 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fmaxp_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseAdvSimd)
|
||||||
|
{
|
||||||
|
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FmaxpS);
|
||||||
|
}
|
||||||
|
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse2ScalarPairwiseOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSse41ProcessNaNsOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true);
|
||||||
|
}, scalar: true, op1, op2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarPairwiseOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fmaxp_V(ArmEmitterContext context)
|
public static void Fmaxp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.UseAdvSimd)
|
if (Optimizations.UseAdvSimd)
|
||||||
@@ -1081,6 +1106,31 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fminp_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseAdvSimd)
|
||||||
|
{
|
||||||
|
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FminpS);
|
||||||
|
}
|
||||||
|
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse2ScalarPairwiseOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSse41ProcessNaNsOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false);
|
||||||
|
}, scalar: true, op1, op2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarPairwiseOpF(context, (op1, op2) =>
|
||||||
|
{
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fminp_V(ArmEmitterContext context)
|
public static void Fminp_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.UseAdvSimd)
|
if (Optimizations.UseAdvSimd)
|
||||||
|
@@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
|
|||||||
15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0, // S
|
15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0, // S
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
|
public const long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
|
||||||
|
|
||||||
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
|
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
|
||||||
{
|
{
|
||||||
|
@@ -228,6 +228,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Fmaxnmp_S,
|
Fmaxnmp_S,
|
||||||
Fmaxnmp_V,
|
Fmaxnmp_V,
|
||||||
Fmaxnmv_V,
|
Fmaxnmv_V,
|
||||||
|
Fmaxp_S,
|
||||||
Fmaxp_V,
|
Fmaxp_V,
|
||||||
Fmaxv_V,
|
Fmaxv_V,
|
||||||
Fmin_S,
|
Fmin_S,
|
||||||
@@ -237,6 +238,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Fminnmp_S,
|
Fminnmp_S,
|
||||||
Fminnmp_V,
|
Fminnmp_V,
|
||||||
Fminnmv_V,
|
Fminnmv_V,
|
||||||
|
Fminp_S,
|
||||||
Fminp_V,
|
Fminp_V,
|
||||||
Fminv_V,
|
Fminv_V,
|
||||||
Fmla_Se,
|
Fmla_Se,
|
||||||
|
@@ -1448,6 +1448,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||||
FPRoundingMode.TowardsZero => false,
|
FPRoundingMode.TowardsZero => false,
|
||||||
@@ -2879,6 +2880,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
FPRoundingMode.TowardsMinusInfinity => sign,
|
FPRoundingMode.TowardsMinusInfinity => sign,
|
||||||
FPRoundingMode.TowardsZero => false,
|
FPRoundingMode.TowardsZero => false,
|
||||||
|
@@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 5343; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 5518; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@@ -27,6 +27,26 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Dictionary<TKey, TValue> DeserializeAndUpdateDictionary<TKey, TValue>(Stream stream, Func<Stream, TValue> valueFunc, Func<TKey, TValue, (TKey, TValue)> updateFunc) where TKey : struct
|
||||||
|
{
|
||||||
|
Dictionary<TKey, TValue> dictionary = new();
|
||||||
|
|
||||||
|
int count = DeserializeStructure<int>(stream);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
TKey key = DeserializeStructure<TKey>(stream);
|
||||||
|
TValue value = valueFunc(stream);
|
||||||
|
|
||||||
|
(key, value) = updateFunc(key, value);
|
||||||
|
|
||||||
|
dictionary.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static List<T> DeserializeList<T>(Stream stream) where T : struct
|
public static List<T> DeserializeList<T>(Stream stream) where T : struct
|
||||||
{
|
{
|
||||||
|
@@ -9,10 +9,13 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Timers;
|
||||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
@@ -20,7 +23,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 1866; //! Not to be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 5518; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
|
private static readonly uint[] _migrateInternalVersions = {
|
||||||
|
1866,
|
||||||
|
};
|
||||||
|
|
||||||
private const int SaveInterval = 30; // Seconds.
|
private const int SaveInterval = 30; // Seconds.
|
||||||
|
|
||||||
@@ -28,7 +35,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private readonly Ptc _ptc;
|
private readonly Ptc _ptc;
|
||||||
|
|
||||||
private readonly System.Timers.Timer _timer;
|
private readonly Timer _timer;
|
||||||
|
|
||||||
private readonly ulong _outerHeaderMagic;
|
private readonly ulong _outerHeaderMagic;
|
||||||
|
|
||||||
@@ -51,7 +58,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
_ptc = ptc;
|
_ptc = ptc;
|
||||||
|
|
||||||
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
|
_timer = new Timer(SaveInterval * 1000d);
|
||||||
_timer.Elapsed += PreSave;
|
_timer.Elapsed += PreSave;
|
||||||
|
|
||||||
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||||
@@ -168,7 +175,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outerHeader.InfoFileVersion != InternalVersion)
|
if (outerHeader.InfoFileVersion != InternalVersion && !_migrateInternalVersions.Contains(outerHeader.InfoFileVersion))
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
@@ -211,7 +218,19 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (outerHeader.InfoFileVersion)
|
||||||
|
{
|
||||||
|
case InternalVersion:
|
||||||
ProfiledFuncs = Deserialize(stream);
|
ProfiledFuncs = Deserialize(stream);
|
||||||
|
break;
|
||||||
|
case 1866:
|
||||||
|
ProfiledFuncs = Deserialize(stream, (address, profile) => (address + 0x500000UL, profile));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger.Error?.Print(LogClass.Ptc, $"No migration path for {nameof(outerHeader.InfoFileVersion)} '{outerHeader.InfoFileVersion}'. Discarding cache.");
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Assert(stream.Position == stream.Length);
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
|
|
||||||
@@ -225,9 +244,14 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream)
|
private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream, Func<ulong, FuncProfile, (ulong, FuncProfile)> migrateEntryFunc = null)
|
||||||
{
|
{
|
||||||
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
|
if (migrateEntryFunc != null)
|
||||||
|
{
|
||||||
|
return DeserializeAndUpdateDictionary(stream, DeserializeStructure<FuncProfile>, migrateEntryFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeserializeDictionary<ulong, FuncProfile>(stream, DeserializeStructure<FuncProfile>);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||||
@@ -240,7 +264,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
compressedStream.SetLength(0L);
|
compressedStream.SetLength(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
private void PreSave(object source, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
_waitEvent.Reset();
|
_waitEvent.Reset();
|
||||||
|
|
||||||
@@ -277,7 +301,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
|
Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
|
||||||
|
|
||||||
stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
stream.Seek(Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -288,7 +312,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
Debug.Assert(stream.Position == stream.Length);
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
|
|
||||||
stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
stream.Seek(Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||||
Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
|
Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
|
||||||
|
|
||||||
stream.Seek(0L, SeekOrigin.Begin);
|
stream.Seek(0L, SeekOrigin.Begin);
|
||||||
@@ -332,7 +356,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||||
{
|
{
|
||||||
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
|
SerializeDictionary(stream, profiledFuncs, SerializeStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)]
|
||||||
|
@@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
_stillRunning = true;
|
_stillRunning = true;
|
||||||
_updaterThread = new Thread(Update)
|
_updaterThread = new Thread(Update)
|
||||||
{
|
{
|
||||||
Name = "HardwareDeviceDriver.OpenAL"
|
Name = "HardwareDeviceDriver.OpenAL",
|
||||||
};
|
};
|
||||||
|
|
||||||
_updaterThread.Start();
|
_updaterThread.Start();
|
||||||
|
@@ -67,7 +67,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
{
|
{
|
||||||
DriverIdentifier = buffer.DataPointer,
|
DriverIdentifier = buffer.DataPointer,
|
||||||
BufferId = AL.GenBuffer(),
|
BufferId = AL.GenBuffer(),
|
||||||
SampleCount = GetSampleCount(buffer)
|
SampleCount = GetSampleCount(buffer),
|
||||||
};
|
};
|
||||||
|
|
||||||
AL.BufferData(driverBuffer.BufferId, _targetFormat, buffer.Data, (int)RequestedSampleRate);
|
AL.BufferData(driverBuffer.BufferId, _targetFormat, buffer.Data, (int)RequestedSampleRate);
|
||||||
|
@@ -7,7 +7,6 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
@@ -111,7 +110,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
channels = (byte)requestedChannelCount,
|
channels = (byte)requestedChannelCount,
|
||||||
format = GetSDL2Format(requestedSampleFormat),
|
format = GetSDL2Format(requestedSampleFormat),
|
||||||
freq = (int)requestedSampleRate,
|
freq = (int)requestedSampleRate,
|
||||||
samples = (ushort)sampleCount
|
samples = (ushort)sampleCount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,6 @@
|
|||||||
Alsa = 3,
|
Alsa = 3,
|
||||||
CoreAudio = 4,
|
CoreAudio = 4,
|
||||||
Wasapi = 5,
|
Wasapi = 5,
|
||||||
Dummy = 6
|
Dummy = 6,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
public enum SoundIoDeviceAim
|
public enum SoundIoDeviceAim
|
||||||
{
|
{
|
||||||
SoundIoDeviceAimInput = 0,
|
SoundIoDeviceAimInput = 0,
|
||||||
SoundIoDeviceAimOutput = 1
|
SoundIoDeviceAimOutput = 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,15 @@
|
|||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:sty="using:FluentAvalonia.Styling">
|
xmlns:sty="using:FluentAvalonia.Styling">
|
||||||
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<MergeResourceInclude Source="/Assets/Styles/Themes.xaml"/>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<sty:FluentAvaloniaTheme PreferSystemTheme="False" />
|
<sty:FluentAvaloniaTheme PreferSystemTheme="False" />
|
||||||
|
<StyleInclude Source="/Assets/Styles/Styles.xaml"/>
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
</Application>
|
</Application>
|
@@ -3,9 +3,7 @@ using Avalonia.Controls.ApplicationLifetimes;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.Styling;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
@@ -25,6 +23,11 @@ namespace Ryujinx.Ava
|
|||||||
Name = $"Ryujinx {Program.Version}";
|
Name = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
Process.Start("/usr/bin/defaults", "write org.ryujinx.Ryujinx ApplePressAndHoldEnabled -bool false");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
@@ -67,7 +70,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (result == UserResult.Yes)
|
if (result == UserResult.Yes)
|
||||||
{
|
{
|
||||||
var path = Process.GetCurrentProcess().MainModule.FileName;
|
var path = Environment.ProcessPath;
|
||||||
var proc = Process.Start(path, CommandLineState.Arguments);
|
var proc = Process.Start(path, CommandLineState.Arguments);
|
||||||
desktop.Shutdown();
|
desktop.Shutdown();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
@@ -90,8 +93,6 @@ namespace Ryujinx.Ava
|
|||||||
string themePath = ConfigurationState.Instance.Ui.CustomThemePath;
|
string themePath = ConfigurationState.Instance.Ui.CustomThemePath;
|
||||||
bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme;
|
bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme;
|
||||||
|
|
||||||
const string BaseStyleUrl = "avares://Ryujinx.Ava/Assets/Styles/Base{0}.xaml";
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(baseStyle))
|
if (string.IsNullOrWhiteSpace(baseStyle))
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark";
|
ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark";
|
||||||
@@ -99,31 +100,12 @@ namespace Ryujinx.Ava
|
|||||||
baseStyle = ConfigurationState.Instance.Ui.BaseStyle;
|
baseStyle = ConfigurationState.Instance.Ui.BaseStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = AvaloniaLocator.Current.GetService<FluentAvaloniaTheme>();
|
RequestedThemeVariant = baseStyle switch
|
||||||
|
|
||||||
theme.RequestedTheme = baseStyle;
|
|
||||||
|
|
||||||
var currentStyles = this.Styles;
|
|
||||||
|
|
||||||
// Remove all styles except the base style.
|
|
||||||
if (currentStyles.Count > 1)
|
|
||||||
{
|
{
|
||||||
currentStyles.RemoveRange(1, currentStyles.Count - 1);
|
"Light" => ThemeVariant.Light,
|
||||||
}
|
"Dark" => ThemeVariant.Dark,
|
||||||
|
_ => ThemeVariant.Default
|
||||||
IStyle newStyles = null;
|
};
|
||||||
|
|
||||||
// Load requested style, and fallback to Dark theme if loading failed.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, baseStyle), UriKind.Absolute));
|
|
||||||
}
|
|
||||||
catch (XamlLoadException)
|
|
||||||
{
|
|
||||||
newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, "Dark"), UriKind.Absolute));
|
|
||||||
}
|
|
||||||
|
|
||||||
currentStyles.Add(newStyles);
|
|
||||||
|
|
||||||
if (enableCustomTheme)
|
if (enableCustomTheme)
|
||||||
{
|
{
|
||||||
@@ -134,7 +116,7 @@ namespace Ryujinx.Ava
|
|||||||
var themeContent = File.ReadAllText(themePath);
|
var themeContent = File.ReadAllText(themePath);
|
||||||
var customStyle = AvaloniaRuntimeXamlLoader.Parse<IStyle>(themeContent);
|
var customStyle = AvaloniaRuntimeXamlLoader.Parse<IStyle>(themeContent);
|
||||||
|
|
||||||
currentStyles.Add(customStyle);
|
Styles.Add(customStyle);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Rendering;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.Dummy;
|
using Ryujinx.Audio.Backends.Dummy;
|
||||||
@@ -26,6 +28,7 @@ using Ryujinx.Graphics.GAL.Multithreading;
|
|||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
@@ -41,7 +44,6 @@ using SixLabors.ImageSharp;
|
|||||||
using SixLabors.ImageSharp.Formats.Png;
|
using SixLabors.ImageSharp.Formats.Png;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
using SPB.Graphics.Exceptions;
|
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -50,10 +52,13 @@ using System.IO;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
||||||
|
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||||
|
using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
using MouseButton = Ryujinx.Input.MouseButton;
|
using MouseButton = Ryujinx.Input.MouseButton;
|
||||||
|
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||||
using Size = Avalonia.Size;
|
using Size = Avalonia.Size;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
|
||||||
@@ -66,9 +71,9 @@ namespace Ryujinx.Ava
|
|||||||
private const int TargetFps = 60;
|
private const int TargetFps = 60;
|
||||||
private const float VolumeDelta = 0.05f;
|
private const float VolumeDelta = 0.05f;
|
||||||
|
|
||||||
private static readonly Cursor InvisibleCursor = new(StandardCursorType.None);
|
private static readonly Cursor _invisibleCursor = new(StandardCursorType.None);
|
||||||
private readonly IntPtr InvisibleCursorWin;
|
private readonly IntPtr _invisibleCursorWin;
|
||||||
private readonly IntPtr DefaultCursorWin;
|
private readonly IntPtr _defaultCursorWin;
|
||||||
|
|
||||||
private readonly long _ticksPerFrame;
|
private readonly long _ticksPerFrame;
|
||||||
private readonly Stopwatch _chrono;
|
private readonly Stopwatch _chrono;
|
||||||
@@ -81,7 +86,7 @@ namespace Ryujinx.Ava
|
|||||||
private readonly MainWindowViewModel _viewModel;
|
private readonly MainWindowViewModel _viewModel;
|
||||||
private readonly IKeyboard _keyboardInterface;
|
private readonly IKeyboard _keyboardInterface;
|
||||||
private readonly TopLevel _topLevel;
|
private readonly TopLevel _topLevel;
|
||||||
public RendererHost _rendererHost;
|
public RendererHost RendererHost;
|
||||||
|
|
||||||
private readonly GraphicsDebugLevel _glLogLevel;
|
private readonly GraphicsDebugLevel _glLogLevel;
|
||||||
private float _newVolume;
|
private float _newVolume;
|
||||||
@@ -94,7 +99,7 @@ namespace Ryujinx.Ava
|
|||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private bool _renderingStarted;
|
private bool _renderingStarted;
|
||||||
|
|
||||||
private ManualResetEvent _gpuDoneEvent;
|
private readonly ManualResetEvent _gpuDoneEvent;
|
||||||
|
|
||||||
private IRenderer _renderer;
|
private IRenderer _renderer;
|
||||||
private readonly Thread _renderingThread;
|
private readonly Thread _renderingThread;
|
||||||
@@ -150,28 +155,28 @@ namespace Ryujinx.Ava
|
|||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
|
||||||
_rendererHost = renderer;
|
RendererHost = renderer;
|
||||||
|
|
||||||
_chrono = new Stopwatch();
|
_chrono = new Stopwatch();
|
||||||
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
||||||
|
|
||||||
if (ApplicationPath.StartsWith("@SystemContent"))
|
if (ApplicationPath.StartsWith("@SystemContent"))
|
||||||
{
|
{
|
||||||
ApplicationPath = _viewModel.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
ApplicationPath = VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
||||||
|
|
||||||
_isFirmwareTitle = true;
|
_isFirmwareTitle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.HideCursor.Event += HideCursorState_Changed;
|
ConfigurationState.Instance.HideCursor.Event += HideCursorState_Changed;
|
||||||
|
|
||||||
_topLevel.PointerMoved += TopLevel_PointerEnterOrMoved;
|
_topLevel.PointerMoved += TopLevel_PointerEnteredOrMoved;
|
||||||
_topLevel.PointerEnter += TopLevel_PointerEnterOrMoved;
|
_topLevel.PointerEntered += TopLevel_PointerEnteredOrMoved;
|
||||||
_topLevel.PointerLeave += TopLevel_PointerLeave;
|
_topLevel.PointerExited += TopLevel_PointerExited;
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
InvisibleCursorWin = CreateEmptyCursor();
|
_invisibleCursorWin = CreateEmptyCursor();
|
||||||
DefaultCursorWin = CreateArrowCursor();
|
_defaultCursorWin = CreateArrowCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
||||||
@@ -183,6 +188,7 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Graphics.AntiAliasing.Event += UpdateAntiAliasing;
|
ConfigurationState.Instance.Graphics.AntiAliasing.Event += UpdateAntiAliasing;
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
|
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
||||||
|
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
||||||
|
|
||||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
||||||
|
|
||||||
@@ -190,16 +196,14 @@ namespace Ryujinx.Ava
|
|||||||
_gpuDoneEvent = new ManualResetEvent(false);
|
_gpuDoneEvent = new ManualResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TopLevel_PointerEnterOrMoved(object sender, PointerEventArgs e)
|
private void TopLevel_PointerEnteredOrMoved(object sender, PointerEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is MainWindow window)
|
if (sender is MainWindow window)
|
||||||
{
|
{
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
if (_rendererHost.EmbeddedWindow.TransformedBounds != null)
|
|
||||||
{
|
|
||||||
var point = e.GetCurrentPoint(window).Position;
|
var point = e.GetCurrentPoint(window).Position;
|
||||||
var bounds = _rendererHost.EmbeddedWindow.TransformedBounds.Value.Clip;
|
var bounds = RendererHost.EmbeddedWindow.Bounds;
|
||||||
|
|
||||||
_isCursorInRenderer = point.X >= bounds.X &&
|
_isCursorInRenderer = point.X >= bounds.X &&
|
||||||
point.X <= bounds.Width + bounds.X &&
|
point.X <= bounds.Width + bounds.X &&
|
||||||
@@ -207,9 +211,8 @@ namespace Ryujinx.Ava
|
|||||||
point.Y <= bounds.Height + bounds.Y;
|
point.Y <= bounds.Height + bounds.Y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void TopLevel_PointerLeave(object sender, PointerEventArgs e)
|
private void TopLevel_PointerExited(object sender, PointerEventArgs e)
|
||||||
{
|
{
|
||||||
_isCursorInRenderer = false;
|
_isCursorInRenderer = false;
|
||||||
}
|
}
|
||||||
@@ -220,12 +223,17 @@ namespace Ryujinx.Ava
|
|||||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateScalingFilter(object sender, ReactiveEventArgs<Ryujinx.Common.Configuration.ScalingFilter> e)
|
private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
|
||||||
{
|
{
|
||||||
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
|
||||||
|
{
|
||||||
|
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowCursor()
|
private void ShowCursor()
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
@@ -234,7 +242,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
SetCursor(DefaultCursorWin);
|
SetCursor(_defaultCursorWin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -243,11 +251,11 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
_viewModel.Cursor = InvisibleCursor;
|
_viewModel.Cursor = _invisibleCursor;
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
SetCursor(InvisibleCursorWin);
|
SetCursor(_invisibleCursorWin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -256,7 +264,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (_renderer != null)
|
if (_renderer != null)
|
||||||
{
|
{
|
||||||
double scale = _topLevel.PlatformImpl.RenderScaling;
|
double scale = _topLevel.RenderScaling;
|
||||||
|
|
||||||
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
||||||
}
|
}
|
||||||
@@ -276,7 +284,7 @@ namespace Ryujinx.Ava
|
|||||||
string directory = AppDataManager.Mode switch
|
string directory = AppDataManager.Mode switch
|
||||||
{
|
{
|
||||||
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||||
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx"),
|
||||||
};
|
};
|
||||||
|
|
||||||
string path = Path.Combine(directory, filename);
|
string path = Path.Combine(directory, filename);
|
||||||
@@ -305,9 +313,9 @@ namespace Ryujinx.Ava
|
|||||||
image.Mutate(x => x.Flip(FlipMode.Vertical));
|
image.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||||
}
|
}
|
||||||
|
|
||||||
image.SaveAsPng(path, new PngEncoder()
|
image.SaveAsPng(path, new PngEncoder
|
||||||
{
|
{
|
||||||
ColorType = PngColorType.Rgb
|
ColorType = PngColorType.Rgb,
|
||||||
});
|
});
|
||||||
|
|
||||||
image.Dispose();
|
image.Dispose();
|
||||||
@@ -348,9 +356,9 @@ namespace Ryujinx.Ava
|
|||||||
_viewModel.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
_viewModel.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||||
});
|
});
|
||||||
|
|
||||||
_viewModel.SetUIProgressHandlers(Device);
|
_viewModel.SetUiProgressHandlers(Device);
|
||||||
|
|
||||||
_rendererHost.SizeChanged += Window_SizeChanged;
|
RendererHost.BoundsChanged += Window_BoundsChanged;
|
||||||
|
|
||||||
_isActive = true;
|
_isActive = true;
|
||||||
|
|
||||||
@@ -379,7 +387,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<Ryujinx.Common.Configuration.AntiAliasing> e)
|
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
|
||||||
{
|
{
|
||||||
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
|
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
|
||||||
}
|
}
|
||||||
@@ -448,7 +456,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (Device.Processes != null)
|
if (Device.Processes != null)
|
||||||
{
|
{
|
||||||
_viewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText);
|
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
||||||
@@ -458,10 +466,11 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Graphics.ScalingFilter.Event -= UpdateScalingFilter;
|
ConfigurationState.Instance.Graphics.ScalingFilter.Event -= UpdateScalingFilter;
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event -= UpdateScalingFilterLevel;
|
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event -= UpdateScalingFilterLevel;
|
||||||
ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAntiAliasing;
|
ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAntiAliasing;
|
||||||
|
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event -= UpdateColorSpacePassthrough;
|
||||||
|
|
||||||
_topLevel.PointerMoved -= TopLevel_PointerEnterOrMoved;
|
_topLevel.PointerMoved -= TopLevel_PointerEnteredOrMoved;
|
||||||
_topLevel.PointerEnter -= TopLevel_PointerEnterOrMoved;
|
_topLevel.PointerEntered -= TopLevel_PointerEnteredOrMoved;
|
||||||
_topLevel.PointerLeave -= TopLevel_PointerLeave;
|
_topLevel.PointerExited -= TopLevel_PointerExited;
|
||||||
|
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
_gpuCancellationTokenSource.Dispose();
|
_gpuCancellationTokenSource.Dispose();
|
||||||
@@ -477,7 +486,7 @@ namespace Ryujinx.Ava
|
|||||||
_windowsMultimediaTimerResolution = null;
|
_windowsMultimediaTimerResolution = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rendererHost.EmbeddedWindow is EmbeddedWindowOpenGL openGlWindow)
|
if (RendererHost.EmbeddedWindow is EmbeddedWindowOpenGL openGlWindow)
|
||||||
{
|
{
|
||||||
// Try to bind the OpenGL context before calling the shutdown event.
|
// Try to bind the OpenGL context before calling the shutdown event.
|
||||||
openGlWindow.MakeCurrent(false, false);
|
openGlWindow.MakeCurrent(false, false);
|
||||||
@@ -508,7 +517,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
||||||
{
|
{
|
||||||
@@ -526,7 +535,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (result != UserResult.Yes)
|
if (result != UserResult.Yes)
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -535,7 +544,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -558,7 +567,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError, (desktop.MainWindow as MainWindow));
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -727,7 +736,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
renderer = new VulkanRenderer(
|
renderer = new VulkanRenderer(
|
||||||
Vk.GetApi(),
|
Vk.GetApi(),
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowVulkan).CreateSurface,
|
(RendererHost.EmbeddedWindow as EmbeddedWindowVulkan).CreateSurface,
|
||||||
VulkanHelper.GetRequiredInstanceExtensions,
|
VulkanHelper.GetRequiredInstanceExtensions,
|
||||||
ConfigurationState.Instance.Graphics.PreferredGpu.Value);
|
ConfigurationState.Instance.Graphics.PreferredGpu.Value);
|
||||||
}
|
}
|
||||||
@@ -738,18 +747,18 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||||
|
|
||||||
var isGALthreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
var isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||||
if (isGALthreaded)
|
if (isGALThreaded)
|
||||||
{
|
{
|
||||||
renderer = new ThreadedRenderer(renderer);
|
renderer = new ThreadedRenderer(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALthreaded}");
|
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
|
||||||
|
|
||||||
// Initialize Configuration.
|
// Initialize Configuration.
|
||||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB;
|
||||||
|
|
||||||
HLE.HLEConfiguration configuration = new(VirtualFileSystem,
|
HLEConfiguration configuration = new(VirtualFileSystem,
|
||||||
_viewModel.LibHacHorizonManager,
|
_viewModel.LibHacHorizonManager,
|
||||||
ContentManager,
|
ContentManager,
|
||||||
_accountManager,
|
_accountManager,
|
||||||
@@ -780,12 +789,12 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private static IHardwareDeviceDriver InitializeAudio()
|
private static IHardwareDeviceDriver InitializeAudio()
|
||||||
{
|
{
|
||||||
var availableBackends = new List<AudioBackend>()
|
var availableBackends = new List<AudioBackend>
|
||||||
{
|
{
|
||||||
AudioBackend.SDL2,
|
AudioBackend.SDL2,
|
||||||
AudioBackend.SoundIo,
|
AudioBackend.SoundIo,
|
||||||
AudioBackend.OpenAl,
|
AudioBackend.OpenAl,
|
||||||
AudioBackend.Dummy
|
AudioBackend.Dummy,
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value;
|
AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value;
|
||||||
@@ -806,13 +815,11 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
return new T();
|
return new T();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Audio, $"{backend} is not supported, falling back to {nextBackend}.");
|
Logger.Warning?.Print(LogClass.Audio, $"{backend} is not supported, falling back to {nextBackend}.");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IHardwareDeviceDriver deviceDriver = null;
|
IHardwareDeviceDriver deviceDriver = null;
|
||||||
|
|
||||||
@@ -826,7 +833,7 @@ namespace Ryujinx.Ava
|
|||||||
AudioBackend.SDL2 => InitializeAudioBackend<SDL2HardwareDeviceDriver>(AudioBackend.SDL2, nextBackend),
|
AudioBackend.SDL2 => InitializeAudioBackend<SDL2HardwareDeviceDriver>(AudioBackend.SDL2, nextBackend),
|
||||||
AudioBackend.SoundIo => InitializeAudioBackend<SoundIoHardwareDeviceDriver>(AudioBackend.SoundIo, nextBackend),
|
AudioBackend.SoundIo => InitializeAudioBackend<SoundIoHardwareDeviceDriver>(AudioBackend.SoundIo, nextBackend),
|
||||||
AudioBackend.OpenAl => InitializeAudioBackend<OpenALHardwareDeviceDriver>(AudioBackend.OpenAl, nextBackend),
|
AudioBackend.OpenAl => InitializeAudioBackend<OpenALHardwareDeviceDriver>(AudioBackend.OpenAl, nextBackend),
|
||||||
_ => new DummyHardwareDeviceDriver()
|
_ => new DummyHardwareDeviceDriver(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (deviceDriver != null)
|
if (deviceDriver != null)
|
||||||
@@ -841,7 +848,7 @@ namespace Ryujinx.Ava
|
|||||||
return deviceDriver;
|
return deviceDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_SizeChanged(object sender, Size e)
|
private void Window_BoundsChanged(object sender, Size e)
|
||||||
{
|
{
|
||||||
Width = (int)e.Width;
|
Width = (int)e.Width;
|
||||||
Height = (int)e.Height;
|
Height = (int)e.Height;
|
||||||
@@ -879,18 +886,19 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
||||||
|
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.InitializeBackgroundContext(_renderer);
|
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.InitializeBackgroundContext(_renderer);
|
||||||
|
|
||||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||||
|
|
||||||
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
|
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
|
||||||
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||||
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
|
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||||
|
|
||||||
Width = (int)_rendererHost.Bounds.Width;
|
Width = (int)RendererHost.Bounds.Width;
|
||||||
Height = (int)_rendererHost.Bounds.Height;
|
Height = (int)RendererHost.Bounds.Height;
|
||||||
|
|
||||||
_renderer.Window.SetSize((int)(Width * _topLevel.PlatformImpl.RenderScaling), (int)(Height * _topLevel.PlatformImpl.RenderScaling));
|
_renderer.Window.SetSize((int)(Width * _topLevel.RenderScaling), (int)(Height * _topLevel.RenderScaling));
|
||||||
|
|
||||||
_chrono.Start();
|
_chrono.Start();
|
||||||
|
|
||||||
@@ -923,7 +931,7 @@ namespace Ryujinx.Ava
|
|||||||
_viewModel.SwitchToRenderer(false);
|
_viewModel.SwitchToRenderer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device.PresentFrame(() => (_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers());
|
Device.PresentFrame(() => (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_ticks >= _ticksPerFrame)
|
if (_ticks >= _ticksPerFrame)
|
||||||
@@ -941,7 +949,7 @@ namespace Ryujinx.Ava
|
|||||||
_gpuDoneEvent.Set();
|
_gpuDoneEvent.Set();
|
||||||
});
|
});
|
||||||
|
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatus()
|
public void UpdateStatus()
|
||||||
|
@@ -620,6 +620,8 @@
|
|||||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||||
|
"SettingsEnableColorSpacePassthrough": "Color Space Passthrough",
|
||||||
|
"SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.",
|
||||||
"VolumeShort": "Vol",
|
"VolumeShort": "Vol",
|
||||||
"UserProfilesManageSaves": "Manage Saves",
|
"UserProfilesManageSaves": "Manage Saves",
|
||||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||||
|
@@ -1,65 +0,0 @@
|
|||||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
|
||||||
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
|
|
||||||
<Design.PreviewWith>
|
|
||||||
<Border Height="2000" Padding="20">
|
|
||||||
<StackPanel Spacing="5">
|
|
||||||
<TextBlock Text="Code Font Family" />
|
|
||||||
<Grid RowDefinitions="*,Auto">
|
|
||||||
<Menu Grid.Row="1" Width="100">
|
|
||||||
<MenuItem Header="File">
|
|
||||||
<MenuItem Header="Test 1" />
|
|
||||||
<MenuItem Header="Test 2" />
|
|
||||||
<MenuItem Header="Test 3">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Button
|
|
||||||
Name="btnAdd"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Content="Add" />
|
|
||||||
<Button
|
|
||||||
Name="btnRem"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Content="Add" />
|
|
||||||
<TextBox
|
|
||||||
Width="100"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="Rrrrr"
|
|
||||||
UseFloatingWatermark="True"
|
|
||||||
Watermark="Hello" />
|
|
||||||
<CheckBox>Test Check</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Design.PreviewWith>
|
|
||||||
<Styles.Resources>
|
|
||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
|
||||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
|
||||||
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
|
||||||
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
|
|
||||||
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
|
|
||||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark3">#FF00525E</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight1">#FF00dbff</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight2">#FF19dfff</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight3">#FF33e3ff</Color>
|
|
||||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
|
||||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
|
||||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
|
||||||
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
|
||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
|
||||||
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
|
||||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
|
||||||
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
|
||||||
</Styles.Resources>
|
|
||||||
</Styles>
|
|
@@ -1,57 +0,0 @@
|
|||||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
|
||||||
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
|
|
||||||
<Design.PreviewWith>
|
|
||||||
<Border Height="2000" Padding="20">
|
|
||||||
<StackPanel Spacing="5">
|
|
||||||
<TextBlock Text="Code Font Family" />
|
|
||||||
<Grid RowDefinitions="*,Auto">
|
|
||||||
<Menu Grid.Row="1" Width="100">
|
|
||||||
<MenuItem Header="File">
|
|
||||||
<MenuItem Header="Test 1" />
|
|
||||||
<MenuItem Header="Test 2" />
|
|
||||||
<MenuItem Header="Test 3">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Button
|
|
||||||
Name="btnAdd"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Content="Add" />
|
|
||||||
<Button
|
|
||||||
Name="btnRem"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Content="Add" />
|
|
||||||
<TextBox
|
|
||||||
Width="100"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="Rrrrr"
|
|
||||||
UseFloatingWatermark="True"
|
|
||||||
Watermark="Hello" />
|
|
||||||
<CheckBox>Test Check</CheckBox>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Design.PreviewWith>
|
|
||||||
<Styles.Resources>
|
|
||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
|
||||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
|
||||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
|
|
||||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
|
||||||
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
|
|
||||||
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
|
|
||||||
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
|
||||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
|
||||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
|
||||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
|
||||||
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
|
||||||
</Styles.Resources>
|
|
||||||
</Styles>
|
|
@@ -3,17 +3,20 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<Border Height="2000" Padding="20">
|
<Border Height="2000"
|
||||||
|
Padding="20">
|
||||||
<StackPanel Spacing="5">
|
<StackPanel Spacing="5">
|
||||||
<TextBlock Text="Code Font Family" />
|
<TextBlock Text="Code Font Family" />
|
||||||
<Grid RowDefinitions="*,Auto">
|
<Grid RowDefinitions="*,Auto">
|
||||||
<Menu Grid.Row="1" Width="100">
|
<Menu Grid.Row="1"
|
||||||
|
Width="100">
|
||||||
<MenuItem Header="File">
|
<MenuItem Header="File">
|
||||||
<MenuItem Header="Test 1" />
|
<MenuItem Header="Test 1" />
|
||||||
<MenuItem Header="Test 2" />
|
<MenuItem Header="Test 2" />
|
||||||
<MenuItem Header="Test 3">
|
<MenuItem Header="Test 3">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
<CheckBox Margin="0"
|
||||||
|
IsChecked="{ReflectionBinding Checkbox, Mode=TwoWay}" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@@ -42,57 +45,80 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
<Style Selector="Border.small">
|
<Style Selector="Border.small">
|
||||||
<Setter Property="Width" Value="100" />
|
<Setter Property="Width"
|
||||||
|
Value="100" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.normal">
|
<Style Selector="Border.normal">
|
||||||
<Setter Property="Width" Value="130" />
|
<Setter Property="Width"
|
||||||
|
Value="130" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.large">
|
<Style Selector="Border.large">
|
||||||
<Setter Property="Width" Value="160" />
|
<Setter Property="Width"
|
||||||
|
Value="160" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.huge">
|
<Style Selector="Border.huge">
|
||||||
<Setter Property="Width" Value="200" />
|
<Setter Property="Width"
|
||||||
|
Value="200" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.settings">
|
<Style Selector="Border.settings">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeDarkColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
Value="{DynamicResource ThemeDarkColor}" />
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderBrush"
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
Value="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
||||||
|
<Setter Property="BorderThickness"
|
||||||
|
Value="1" />
|
||||||
|
<Setter Property="CornerRadius"
|
||||||
|
Value="5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Image.small">
|
<Style Selector="Image.small">
|
||||||
<Setter Property="Width" Value="50" />
|
<Setter Property="Width"
|
||||||
|
Value="50" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Image.normal">
|
<Style Selector="Image.normal">
|
||||||
<Setter Property="Width" Value="80" />
|
<Setter Property="Width"
|
||||||
|
Value="80" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Image.large">
|
<Style Selector="Image.large">
|
||||||
<Setter Property="Width" Value="100" />
|
<Setter Property="Width"
|
||||||
|
Value="100" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Image.huge">
|
<Style Selector="Image.huge">
|
||||||
<Setter Property="Width" Value="120" />
|
<Setter Property="Width"
|
||||||
|
Value="120" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="#TitleBarHost > Image">
|
<Style Selector="#TitleBarHost > Image">
|
||||||
<Setter Property="Margin" Value="10" />
|
<Setter Property="Margin"
|
||||||
|
Value="10" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="#TitleBarHost > Label">
|
<Style Selector="#TitleBarHost > Label">
|
||||||
<Setter Property="Margin" Value="5" />
|
<Setter Property="Margin"
|
||||||
<Setter Property="FontSize" Value="14" />
|
Value="5" />
|
||||||
|
<Setter Property="FontSize"
|
||||||
|
Value="14" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Button.SystemCaption">
|
<Style Selector="Button.SystemCaption">
|
||||||
<Setter Property="MinWidth" Value="10" />
|
<Setter Property="MinWidth"
|
||||||
|
Value="10" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridColumnHeader">
|
<Style Selector="DataGridColumnHeader">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
|
<Setter Property="Foreground"
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
Value="{DynamicResource ThemeForegroundBrush}" />
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="HorizontalContentAlignment"
|
||||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
Value="Center" />
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
<Setter Property="BorderThickness"
|
||||||
<Setter Property="SeparatorBrush" Value="{DynamicResource ThemeControlBorderColor}" />
|
Value="1" />
|
||||||
<Setter Property="Padding" Value="5" />
|
<Setter Property="VerticalContentAlignment"
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeContentBackgroundColor}" />
|
Value="Center" />
|
||||||
|
<Setter Property="SeparatorBrush"
|
||||||
|
Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
|
<Setter Property="Padding"
|
||||||
|
Value="5" />
|
||||||
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource ThemeContentBackgroundColor}" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate>
|
<ControlTemplate>
|
||||||
<Grid Background="{TemplateBinding Background}" ColumnDefinitions="*,Auto">
|
<Grid Background="{TemplateBinding Background}"
|
||||||
|
ColumnDefinitions="*,Auto">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="{TemplateBinding Padding}"
|
Margin="{TemplateBinding Padding}"
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
@@ -122,193 +148,240 @@
|
|||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGrid">
|
<Style Selector="DataGrid">
|
||||||
<Setter Property="RowBackground" Value="{DynamicResource ThemeAccentBrush4}" />
|
<Setter Property="RowBackground"
|
||||||
<Setter Property="AlternatingRowBackground" Value="#00FFFFFF" />
|
Value="{DynamicResource ThemeAccentBrush4}" />
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
|
Value="{DynamicResource ThemeBackgroundBrush}" />
|
||||||
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" />
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource ThemeBorderLowColor}" />
|
||||||
|
<Setter Property="BorderThickness"
|
||||||
|
Value="{DynamicResource ThemeBorderThickness}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridRow:selected:focus /template/ Rectangle#BackgroundRectangle">
|
<Style Selector="DataGridRow:selected:focus /template/ Rectangle#BackgroundRectangle">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
<Setter Property="Fill"
|
||||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedBackgroundOpacity}" />
|
Value="{DynamicResource SystemAccentColor}" />
|
||||||
|
<Setter Property="Opacity"
|
||||||
|
Value="{DynamicResource DataGridRowSelectedBackgroundOpacity}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridRow:pointerover /template/ Rectangle#BackgroundRectangle">
|
<Style Selector="DataGridRow:pointerover /template/ Rectangle#BackgroundRectangle">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemListLowColor}" />
|
<Setter Property="Fill"
|
||||||
|
Value="{DynamicResource SystemListLowColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
|
<Style Selector="DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
<Setter Property="Fill"
|
||||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedUnfocusedBackgroundOpacity}" />
|
Value="{DynamicResource SystemAccentColor}" />
|
||||||
|
<Setter Property="Opacity"
|
||||||
|
Value="{DynamicResource DataGridRowSelectedUnfocusedBackgroundOpacity}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridRow:selected:pointerover /template/ Rectangle#BackgroundRectangle">
|
<Style Selector="DataGridRow:selected:pointerover /template/ Rectangle#BackgroundRectangle">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
<Setter Property="Fill"
|
||||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}" />
|
Value="{DynamicResource SystemAccentColor}" />
|
||||||
|
<Setter Property="Opacity"
|
||||||
|
Value="{DynamicResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridRow:selected:pointerover:focus /template/ Rectangle#BackgroundRectangle">
|
<Style Selector="DataGridRow:selected:pointerover:focus /template/ Rectangle#BackgroundRectangle">
|
||||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
<Setter Property="Fill"
|
||||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredBackgroundOpacity}" />
|
Value="{DynamicResource SystemAccentColor}" />
|
||||||
|
<Setter Property="Opacity"
|
||||||
|
Value="{DynamicResource DataGridRowSelectedHoveredBackgroundOpacity}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridCell">
|
<Style Selector="DataGridCell">
|
||||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
<Setter Property="HorizontalAlignment"
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
Value="Center" />
|
||||||
|
<Setter Property="HorizontalContentAlignment"
|
||||||
|
Value="Center" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridCell.Left">
|
<Style Selector="DataGridCell.Left">
|
||||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
<Setter Property="HorizontalAlignment"
|
||||||
|
Value="Left" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="CheckBox">
|
<Style Selector="CheckBox">
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderThickness"
|
||||||
|
Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="MenuItem">
|
<Style Selector="MenuItem">
|
||||||
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
<Setter Property="Height"
|
||||||
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
Value="{DynamicResource MenuItemHeight}" />
|
||||||
<Setter Property="FontSize" Value="12" />
|
<Setter Property="Padding"
|
||||||
|
Value="{DynamicResource MenuItemPadding}" />
|
||||||
|
<Setter Property="FontSize"
|
||||||
|
Value="12" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="MenuItem:selected /template/ Border#root">
|
<Style Selector="MenuItem:selected /template/ Border#root">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlBorderColor}" />
|
Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TabItem > ScrollViewer">
|
<Style Selector="TabItem > ScrollViewer">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="Margin" Value="0,-5,0,0" />
|
Value="{DynamicResource ThemeBackgroundColor}" />
|
||||||
|
<Setter Property="Margin"
|
||||||
|
Value="0,-5,0,0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TabItem > ScrollViewer > Border">
|
<Style Selector="TabItem > ScrollViewer > Border">
|
||||||
<Setter Property="BorderThickness" Value="0,1,0,0" />
|
<Setter Property="BorderThickness"
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundColor}" />
|
Value="0,1,0,0" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource HighlightBrush}" />
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource ThemeBackgroundColor}" />
|
||||||
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource HighlightBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Button">
|
<Style Selector="Button">
|
||||||
<Setter Property="MinWidth" Value="80" />
|
<Setter Property="MinWidth"
|
||||||
|
Value="80" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ProgressBar /template/ Border#ProgressBarTrack">
|
<Style Selector="ProgressBar /template/ Border#ProgressBarTrack">
|
||||||
<Setter Property="IsVisible" Value="False" />
|
<Setter Property="IsVisible"
|
||||||
|
Value="False" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ToggleButton">
|
<Style Selector="ToggleButton">
|
||||||
<Setter Property="Padding" Value="0,-5,0,0" />
|
<Setter Property="Padding"
|
||||||
|
Value="0,-5,0,0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TabItem">
|
<Style Selector="TabItem">
|
||||||
<Setter Property="FontSize" Value="14" />
|
<Setter Property="FontSize"
|
||||||
<Setter Property="BorderThickness" Value="0,0,1,0" />
|
Value="14" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
<Setter Property="BorderThickness"
|
||||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
Value="0,0,1,0" />
|
||||||
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||||
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource SystemAccentColorLight2}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TabItem:pointerover">
|
<Style Selector="TabItem:pointerover">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
<Setter Property="Foreground"
|
||||||
|
Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TabItem:selected">
|
<Style Selector="TabItem:selected">
|
||||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeBackgroundColor}" />
|
Value="{DynamicResource SystemAccentColorLight2}" />
|
||||||
|
<Setter Property="Foreground"
|
||||||
|
Value="{DynamicResource ThemeBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBlock">
|
<Style Selector="TextBlock">
|
||||||
<Setter Property="Margin" Value="{DynamicResource TextMargin}" />
|
<Setter Property="Margin"
|
||||||
<Setter Property="FontSize" Value="{DynamicResource FontSize}" />
|
Value="{DynamicResource TextMargin}" />
|
||||||
<Setter Property="VerticalAlignment" Value="Center" />
|
<Setter Property="FontSize"
|
||||||
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
Value="{DynamicResource FontSize}" />
|
||||||
|
<Setter Property="VerticalAlignment"
|
||||||
|
Value="Center" />
|
||||||
|
<Setter Property="TextWrapping"
|
||||||
|
Value="WrapWithOverflow" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBlock.h1">
|
<Style Selector="TextBlock.h1">
|
||||||
<Setter Property="Margin" Value="{DynamicResource TextMargin}" />
|
<Setter Property="Margin"
|
||||||
<Setter Property="VerticalAlignment" Value="Center" />
|
Value="{DynamicResource TextMargin}" />
|
||||||
<Setter Property="FontWeight" Value="Bold" />
|
<Setter Property="VerticalAlignment"
|
||||||
<Setter Property="FontSize" Value="16" />
|
Value="Center" />
|
||||||
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
<Setter Property="FontWeight"
|
||||||
|
Value="Bold" />
|
||||||
|
<Setter Property="FontSize"
|
||||||
|
Value="16" />
|
||||||
|
<Setter Property="TextWrapping"
|
||||||
|
Value="WrapWithOverflow" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Separator">
|
<Style Selector="Separator">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeControlBorderColor}" />
|
Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
<Setter Property="MinHeight" Value="1" />
|
<Setter Property="Foreground"
|
||||||
|
Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
|
<Setter Property="MinHeight"
|
||||||
|
Value="1" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle">
|
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle">
|
||||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
<Setter Property="Background"
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeBackgroundColor}" />
|
Value="{DynamicResource SystemAccentColorLight2}" />
|
||||||
|
<Setter Property="Foreground"
|
||||||
|
Value="{DynamicResource ThemeBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DatePickerPresenter">
|
<Style Selector="DatePickerPresenter">
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderThickness"
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
Value="1" />
|
||||||
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="DataGridCell">
|
<Style Selector="DataGridCell">
|
||||||
<Setter Property="FontSize" Value="14" />
|
<Setter Property="FontSize"
|
||||||
|
Value="14" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="CheckBox TextBlock">
|
<Style Selector="CheckBox TextBlock">
|
||||||
<Setter Property="Margin" Value="0,5,0,0" />
|
<Setter Property="Margin"
|
||||||
|
Value="0,5,0,0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ContextMenu">
|
<Style Selector="ContextMenu">
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderBrush}" />
|
<Setter Property="BorderBrush"
|
||||||
<Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
|
Value="{DynamicResource MenuFlyoutPresenterBorderBrush}" />
|
||||||
|
<Setter Property="BorderThickness"
|
||||||
|
Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBox">
|
<Style Selector="TextBox">
|
||||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
<Setter Property="VerticalContentAlignment"
|
||||||
|
Value="Center" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBox.NumberBoxTextBoxStyle">
|
<Style Selector="TextBox.NumberBoxTextBoxStyle">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
|
<Setter Property="Foreground"
|
||||||
|
Value="{DynamicResource ThemeForegroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBox ListBoxItem">
|
<Style Selector="ListBox ListBoxItem">
|
||||||
<Setter Property="Padding" Value="0" />
|
<Setter Property="Padding"
|
||||||
<Setter Property="Margin" Value="0" />
|
Value="0" />
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
<Setter Property="Margin"
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
Value="0" />
|
||||||
<Setter Property="BorderThickness" Value="2"/>
|
<Setter Property="CornerRadius"
|
||||||
<Style.Animations>
|
Value="5" />
|
||||||
<Animation Duration="0:0:0.7">
|
<Setter Property="Background"
|
||||||
<KeyFrame Cue="0%">
|
Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
<Setter Property="MaxHeight" Value="0" />
|
<Setter Property="BorderThickness"
|
||||||
<Setter Property="Opacity" Value="0.0" />
|
Value="2"/>
|
||||||
</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>
|
||||||
<Style Selector="ListBox ListBoxItem:selected /template/ ContentPresenter">
|
<Style Selector="ListBox ListBoxItem:selected /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBox">
|
||||||
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource ThemeContentBackgroundColor}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="FlyoutPresenter, ContextMenu, MenuFlyoutPresenter">
|
||||||
|
<Setter Property="BorderBrush"
|
||||||
|
Value="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBox ListBoxItem:pointerover /template/ ContentPresenter">
|
<Style Selector="ListBox ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
<Setter Property="Background"
|
||||||
|
Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Styles.Resources>
|
<Styles.Resources>
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
||||||
<StaticResource x:Key="ListViewItemBackgroundSelected" ResourceKey="ThemeAccentColorBrush" />
|
Color="{DynamicResource SystemAccentColor}" />
|
||||||
<StaticResource x:Key="ListViewItemBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
|
<StaticResource x:Key="ListViewItemBackgroundSelected"
|
||||||
<StaticResource x:Key="ListViewItemBackgroundPointerOver" ResourceKey="SystemAccentColorDark2" />
|
ResourceKey="ThemeAccentColorBrush" />
|
||||||
<StaticResource x:Key="ListViewItemBackgroundSelectedPressed" ResourceKey="ThemeAccentColorBrush" />
|
<StaticResource x:Key="ListViewItemBackgroundPressed"
|
||||||
<StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver" ResourceKey="SystemAccentColorDark2" />
|
ResourceKey="SystemAccentColorDark1" />
|
||||||
|
<StaticResource x:Key="ListViewItemBackgroundPointerOver"
|
||||||
|
ResourceKey="SystemAccentColorDark2" />
|
||||||
|
<StaticResource x:Key="ListViewItemBackgroundSelectedPressed"
|
||||||
|
ResourceKey="ThemeAccentColorBrush" />
|
||||||
|
<StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver"
|
||||||
|
ResourceKey="SystemAccentColorDark2" />
|
||||||
<SolidColorBrush
|
<SolidColorBrush
|
||||||
x:Key="DataGridGridLinesBrush"
|
x:Key="DataGridGridLinesBrush"
|
||||||
Opacity="0.4"
|
Opacity="0.4"
|
||||||
Color="{DynamicResource SystemBaseMediumLowColor}" />
|
Color="{DynamicResource SystemBaseMediumLowColor}" />
|
||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
<SolidColorBrush x:Key="MenuFlyoutPresenterBorderBrush" Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
<SolidColorBrush x:Key="FlyoutBorderThemeBrush" Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
<SolidColorBrush x:Key="SplitButtonBackgroundChecked"
|
||||||
<SolidColorBrush x:Key="ListBoxBackground" Color="{DynamicResource ThemeContentBackgroundColor}" />
|
Color="#00E81123" />
|
||||||
<SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource ThemeForegroundColor}" />
|
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPointerOver"
|
||||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
Color="#00E81123" />
|
||||||
<SolidColorBrush x:Key="SplitButtonBackgroundChecked" Color="#00E81123" />
|
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPressed"
|
||||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPointerOver" Color="#00E81123" />
|
Color="#00E81123" />
|
||||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPressed" Color="#00E81123" />
|
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled"
|
||||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled" Color="#00E81123" />
|
Color="#00E81123" />
|
||||||
<Thickness x:Key="PageMargin">40 0 40 0</Thickness>
|
<Thickness x:Key="PageMargin">40 0 40 0</Thickness>
|
||||||
<Thickness x:Key="Margin">0 5 0 5</Thickness>
|
<Thickness x:Key="Margin">0 5 0 5</Thickness>
|
||||||
<Thickness x:Key="MenuItemPadding">5 0 5 0</Thickness>
|
<Thickness x:Key="MenuItemPadding">5 0 5 0</Thickness>
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#00000000</Color>
|
|
||||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
|
|
||||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
|
||||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
|
||||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
|
||||||
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
|
|
||||||
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
|
|
||||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
|
||||||
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
|
||||||
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||||
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||||
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||||
|
85
src/Ryujinx.Ava/Assets/Styles/Themes.xaml
Normal file
85
src/Ryujinx.Ava/Assets/Styles/Themes.xaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<ResourceDictionary.ThemeDictionaries>
|
||||||
|
<ResourceDictionary x:Key="Default">
|
||||||
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
|
Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
||||||
|
Color="{DynamicResource SystemAccentColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentBrush4"
|
||||||
|
Color="{DynamicResource ThemeAccentColor4}" />
|
||||||
|
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
|
||||||
|
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||||
|
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
|
||||||
|
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
|
||||||
|
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||||
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
|
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
||||||
|
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
|
||||||
|
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
|
||||||
|
</ResourceDictionary>
|
||||||
|
<ResourceDictionary x:Key="Light">
|
||||||
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
|
Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
||||||
|
Color="{DynamicResource SystemAccentColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentBrush4"
|
||||||
|
Color="{DynamicResource ThemeAccentColor4}" />
|
||||||
|
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
|
||||||
|
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||||
|
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
|
||||||
|
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
|
||||||
|
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||||
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
|
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
||||||
|
</ResourceDictionary>
|
||||||
|
<ResourceDictionary x:Key="Dark">
|
||||||
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
|
Color="{DynamicResource DataGridSelectionColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
||||||
|
Color="{DynamicResource SystemAccentColor}" />
|
||||||
|
<SolidColorBrush x:Key="ThemeAccentBrush4"
|
||||||
|
Color="{DynamicResource ThemeAccentColor4}" />
|
||||||
|
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||||
|
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
||||||
|
<Color x:Key="SystemAccentColorDark3">#FF00525E</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight1">#FF00dbff</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight2">#FF19dfff</Color>
|
||||||
|
<Color x:Key="SystemAccentColorLight3">#FF33e3ff</Color>
|
||||||
|
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||||
|
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||||
|
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||||
|
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
||||||
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||||
|
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||||
|
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||||
|
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</ResourceDictionary.ThemeDictionaries>
|
||||||
|
</ResourceDictionary>
|
@@ -1,5 +1,5 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.Notifications;
|
using Avalonia.Controls.Notifications;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Account;
|
using LibHac.Account;
|
||||||
@@ -18,7 +18,6 @@ using Ryujinx.Ava.UI.Helpers;
|
|||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
@@ -27,6 +26,7 @@ using System.Buffers;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ApplicationId = LibHac.Ncm.ApplicationId;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Common
|
namespace Ryujinx.Ava.Common
|
||||||
@@ -57,7 +57,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"Creating save directory for Title: {titleName} [{titleId:x16}]");
|
Logger.Info?.Print(LogClass.Application, $"Creating save directory for Title: {titleName} [{titleId:x16}]");
|
||||||
|
|
||||||
if (Utilities.IsZeros(controlHolder.ByteSpan))
|
if (controlHolder.ByteSpan.IsZeros())
|
||||||
{
|
{
|
||||||
// If the current application doesn't have a loaded control property, create a dummy one
|
// If the current application doesn't have a loaded control property, create a dummy one
|
||||||
// and set the savedata sizes so a user savedata will be created.
|
// and set the savedata sizes so a user savedata will be created.
|
||||||
@@ -72,7 +72,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
|
|
||||||
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||||
|
|
||||||
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new ApplicationId(titleId), in control, in user);
|
||||||
if (result.IsFailure())
|
if (result.IsFailure())
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
@@ -114,7 +114,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
|
|
||||||
public static void OpenSaveDir(ulong saveDataId)
|
public static void OpenSaveDir(ulong saveDataId)
|
||||||
{
|
{
|
||||||
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
string saveRootPath = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
||||||
|
|
||||||
if (!Directory.Exists(saveRootPath))
|
if (!Directory.Exists(saveRootPath))
|
||||||
{
|
{
|
||||||
@@ -143,14 +143,20 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||||
{
|
{
|
||||||
OpenFolderDialog folderDialog = new()
|
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||||
};
|
AllowMultiple = false
|
||||||
|
});
|
||||||
|
|
||||||
string destination = await folderDialog.ShowAsync(_owner);
|
if (result.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var destination = result[0].Path.LocalPath;
|
||||||
var cancellationToken = new CancellationTokenSource();
|
var cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
UpdateWaitWindow waitingDialog = new(
|
UpdateWaitWindow waitingDialog = new(
|
||||||
@@ -158,8 +164,6 @@ namespace Ryujinx.Ava.Common
|
|||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(destination))
|
|
||||||
{
|
|
||||||
Thread extractorThread = new(() =>
|
Thread extractorThread = new(() =>
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(waitingDialog.Show);
|
Dispatcher.UIThread.Post(waitingDialog.Show);
|
||||||
@@ -293,13 +297,13 @@ namespace Ryujinx.Ava.Common
|
|||||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
{
|
||||||
extractorThread.Name = "GUI.NcaSectionExtractorThread";
|
Name = "GUI.NcaSectionExtractorThread",
|
||||||
extractorThread.IsBackground = true;
|
IsBackground = true,
|
||||||
|
};
|
||||||
extractorThread.Start();
|
extractorThread.Start();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
@@ -10,6 +10,6 @@ namespace Ryujinx.Ava.Common
|
|||||||
FileType,
|
FileType,
|
||||||
FileSize,
|
FileSize,
|
||||||
Path,
|
Path,
|
||||||
Favorite
|
Favorite,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,6 +11,6 @@
|
|||||||
ResScaleUp,
|
ResScaleUp,
|
||||||
ResScaleDown,
|
ResScaleDown,
|
||||||
VolumeUp,
|
VolumeUp,
|
||||||
VolumeDown
|
VolumeDown,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -21,7 +21,7 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
ReflectionBindingExtension binding = new($"[{keyToUse}]")
|
ReflectionBindingExtension binding = new($"[{keyToUse}]")
|
||||||
{
|
{
|
||||||
Mode = BindingMode.OneWay,
|
Mode = BindingMode.OneWay,
|
||||||
Source = LocaleManager.Instance
|
Source = LocaleManager.Instance,
|
||||||
};
|
};
|
||||||
|
|
||||||
return binding.ProvideValue(serviceProvider);
|
return binding.ProvideValue(serviceProvider);
|
||||||
|
@@ -13,11 +13,11 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
{
|
{
|
||||||
private const string DefaultLanguageCode = "en_US";
|
private const string DefaultLanguageCode = "en_US";
|
||||||
|
|
||||||
private Dictionary<LocaleKeys, string> _localeStrings;
|
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
||||||
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
||||||
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||||
|
|
||||||
public static LocaleManager Instance { get; } = new LocaleManager();
|
public static LocaleManager Instance { get; } = new();
|
||||||
|
|
||||||
public LocaleManager()
|
public LocaleManager()
|
||||||
{
|
{
|
||||||
@@ -126,7 +126,7 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
||||||
{
|
{
|
||||||
var localeStrings = new Dictionary<LocaleKeys, string>();
|
var localeStrings = new Dictionary<LocaleKeys, string>();
|
||||||
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
||||||
|
@@ -120,6 +120,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
_buttonsUserMapping.Clear();
|
_buttonsUserMapping.Clear();
|
||||||
|
|
||||||
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
// Left JoyCon
|
// Left JoyCon
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||||
@@ -143,6 +144,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
|
||||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||||
|
#pragma warning restore IDE0055
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,7 +31,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
_control.KeyDown += OnKeyPress;
|
_control.KeyDown += OnKeyPress;
|
||||||
_control.KeyUp += OnKeyRelease;
|
_control.KeyUp += OnKeyRelease;
|
||||||
_control.TextInput += Control_TextInput;
|
_control.TextInput += Control_TextInput;
|
||||||
_control.AddHandler(InputElement.TextInputEvent, Control_LastChanceTextInput, RoutingStrategies.Bubble);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Control_TextInput(object sender, TextInputEventArgs e)
|
private void Control_TextInput(object sender, TextInputEventArgs e)
|
||||||
@@ -39,12 +38,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
TextInput?.Invoke(this, e.Text);
|
TextInput?.Invoke(this, e.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Control_LastChanceTextInput(object sender, TextInputEventArgs e)
|
|
||||||
{
|
|
||||||
// Swallow event
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<string> OnGamepadConnected
|
public event Action<string> OnGamepadConnected
|
||||||
{
|
{
|
||||||
add { }
|
add { }
|
||||||
|
@@ -143,7 +143,7 @@ namespace Ryujinx.Ava.Input
|
|||||||
AvaKey.OemBackslash,
|
AvaKey.OemBackslash,
|
||||||
|
|
||||||
// NOTE: invalid
|
// NOTE: invalid
|
||||||
AvaKey.None
|
AvaKey.None,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;
|
private static readonly Dictionary<AvaKey, Key> _avaKeyMapping;
|
||||||
|
@@ -31,13 +31,13 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
internal static class Updater
|
internal static class Updater
|
||||||
{
|
{
|
||||||
private const string GitHubApiURL = "https://api.github.com";
|
private const string GitHubApiUrl = "https://api.github.com";
|
||||||
private static readonly GithubReleasesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||||
private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish");
|
private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish");
|
||||||
private static readonly int ConnectionCount = 4;
|
private const int ConnectionCount = 4;
|
||||||
|
|
||||||
private static string _buildVer;
|
private static string _buildVer;
|
||||||
private static string _platformExt;
|
private static string _platformExt;
|
||||||
@@ -46,7 +46,7 @@ namespace Ryujinx.Modules
|
|||||||
private static bool _updateSuccessful;
|
private static bool _updateSuccessful;
|
||||||
private static bool _running;
|
private static bool _running;
|
||||||
|
|
||||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
private static readonly string[] _windowsDependencyDirs = Array.Empty<string>();
|
||||||
|
|
||||||
public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate)
|
public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate)
|
||||||
{
|
{
|
||||||
@@ -99,9 +99,9 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
using HttpClient jsonClient = ConstructHttpClient();
|
using HttpClient jsonClient = ConstructHttpClient();
|
||||||
|
|
||||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
||||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl);
|
||||||
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse);
|
var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
|
||||||
_buildVer = fetched.Name;
|
_buildVer = fetched.Name;
|
||||||
|
|
||||||
foreach (var asset in fetched.Assets)
|
foreach (var asset in fetched.Assets)
|
||||||
@@ -195,8 +195,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch build size information to learn chunk sizes.
|
// Fetch build size information to learn chunk sizes.
|
||||||
using (HttpClient buildSizeClient = ConstructHttpClient())
|
using HttpClient buildSizeClient = ConstructHttpClient();
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
||||||
@@ -212,7 +211,6 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
_buildSize = -1;
|
_buildSize = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
@@ -248,23 +246,22 @@ namespace Ryujinx.Modules
|
|||||||
_updateSuccessful = false;
|
_updateSuccessful = false;
|
||||||
|
|
||||||
// Empty update dir, although it shouldn't ever have anything inside it
|
// Empty update dir, although it shouldn't ever have anything inside it
|
||||||
if (Directory.Exists(UpdateDir))
|
if (Directory.Exists(_updateDir))
|
||||||
{
|
{
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(_updateDir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(UpdateDir);
|
Directory.CreateDirectory(_updateDir);
|
||||||
|
|
||||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
string updateFile = Path.Combine(_updateDir, "update.bin");
|
||||||
|
|
||||||
TaskDialog taskDialog = new()
|
TaskDialog taskDialog = new()
|
||||||
{
|
{
|
||||||
Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
||||||
SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading],
|
SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading],
|
||||||
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||||
Buttons = { },
|
|
||||||
ShowProgressBar = true,
|
ShowProgressBar = true,
|
||||||
XamlRoot = parent
|
XamlRoot = parent,
|
||||||
};
|
};
|
||||||
|
|
||||||
taskDialog.Opened += (s, e) =>
|
taskDialog.Opened += (s, e) =>
|
||||||
@@ -301,7 +298,7 @@ namespace Ryujinx.Modules
|
|||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", ".."));
|
string baseBundlePath = Path.GetFullPath(Path.Combine(executableDirectory, "..", ".."));
|
||||||
string newBundlePath = Path.Combine(UpdateDir, "Ryujinx.app");
|
string newBundlePath = Path.Combine(_updateDir, "Ryujinx.app");
|
||||||
string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh");
|
string updaterScriptPath = Path.Combine(newBundlePath, "Contents", "Resources", "updater.sh");
|
||||||
string currentPid = Environment.ProcessId.ToString();
|
string currentPid = Environment.ProcessId.ToString();
|
||||||
|
|
||||||
@@ -328,7 +325,7 @@ namespace Ryujinx.Modules
|
|||||||
ProcessStartInfo processStart = new(ryuName)
|
ProcessStartInfo processStart = new(ryuName)
|
||||||
{
|
{
|
||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
WorkingDirectory = executableDirectory
|
WorkingDirectory = executableDirectory,
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string argument in CommandLineState.Arguments)
|
foreach (string argument in CommandLineState.Arguments)
|
||||||
@@ -421,11 +418,10 @@ namespace Ryujinx.Modules
|
|||||||
// On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution.
|
// On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution.
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
using (Process xattrProcess = Process.Start("xattr", new List<string> { "-d", "com.apple.quarantine", updateFile }))
|
using Process xattrProcess = Process.Start("xattr", new List<string> { "-d", "com.apple.quarantine", updateFile });
|
||||||
{
|
|
||||||
xattrProcess.WaitForExit();
|
xattrProcess.WaitForExit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -437,8 +433,6 @@ namespace Ryujinx.Modules
|
|||||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||||
|
|
||||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -470,9 +464,8 @@ namespace Ryujinx.Modules
|
|||||||
// We do not want to timeout while downloading
|
// We do not want to timeout while downloading
|
||||||
client.Timeout = TimeSpan.FromDays(1);
|
client.Timeout = TimeSpan.FromDays(1);
|
||||||
|
|
||||||
using (HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result)
|
using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result;
|
||||||
using (Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result)
|
using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
|
||||||
{
|
|
||||||
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
|
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
|
||||||
|
|
||||||
long totalBytes = response.Content.Headers.ContentLength.Value;
|
long totalBytes = response.Content.Headers.ContentLength.Value;
|
||||||
@@ -495,7 +488,6 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
updateFileStream.Write(buffer, 0, readSize);
|
updateFileStream.Write(buffer, 0, readSize);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
InstallUpdate(taskDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
@@ -510,7 +502,7 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile))
|
Thread worker = new(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile))
|
||||||
{
|
{
|
||||||
Name = "Updater.SingleThreadWorker"
|
Name = "Updater.SingleThreadWorker",
|
||||||
};
|
};
|
||||||
|
|
||||||
worker.Start();
|
worker.Start();
|
||||||
@@ -537,10 +529,8 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||||
|
|
||||||
using (FileStream outStream = File.OpenWrite(outPath))
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
{
|
|
||||||
tarStream.CopyEntryContents(outStream);
|
tarStream.CopyEntryContents(outStream);
|
||||||
}
|
|
||||||
|
|
||||||
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
|
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
|
||||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||||
@@ -566,17 +556,19 @@ namespace Ryujinx.Modules
|
|||||||
foreach (ZipEntry zipEntry in zipFile)
|
foreach (ZipEntry zipEntry in zipFile)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
if (zipEntry.IsDirectory) continue;
|
if (zipEntry.IsDirectory)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name);
|
string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||||
|
|
||||||
using (Stream zipStream = zipFile.GetInputStream(zipEntry))
|
using Stream zipStream = zipFile.GetInputStream(zipEntry);
|
||||||
using (FileStream outStream = File.OpenWrite(outPath))
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
{
|
|
||||||
zipStream.CopyTo(outStream);
|
zipStream.CopyTo(outStream);
|
||||||
}
|
|
||||||
|
|
||||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
||||||
|
|
||||||
@@ -597,11 +589,11 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
ExtractTarGzipFile(taskDialog, updateFile, UpdateDir);
|
ExtractTarGzipFile(taskDialog, updateFile, _updateDir);
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsWindows())
|
else if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
ExtractZipFile(taskDialog, updateFile, UpdateDir);
|
ExtractZipFile(taskDialog, updateFile, _updateDir);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -648,10 +640,10 @@ namespace Ryujinx.Modules
|
|||||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
|
|
||||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
|
MoveAllFilesOver(_updatePublishDir, _homeDir, taskDialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(_updateDir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateSuccessful = true;
|
_updateSuccessful = true;
|
||||||
@@ -738,15 +730,15 @@ namespace Ryujinx.Modules
|
|||||||
// NOTE: This method should always reflect the latest build layout.
|
// NOTE: This method should always reflect the latest build layout.
|
||||||
private static IEnumerable<string> EnumerateFilesToDelete()
|
private static IEnumerable<string> EnumerateFilesToDelete()
|
||||||
{
|
{
|
||||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
|
||||||
|
|
||||||
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
||||||
if (_running && !OperatingSystem.IsMacOS())
|
if (_running && !OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
||||||
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||||
var newFiles = Directory.EnumerateFiles(UpdatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||||
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(HomeDir, filename));
|
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
|
||||||
|
|
||||||
// Remove user files from the paths in files.
|
// Remove user files from the paths in files.
|
||||||
files = files.Except(userFiles);
|
files = files.Except(userFiles);
|
||||||
@@ -754,9 +746,9 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
foreach (string dir in WindowsDependencyDirs)
|
foreach (string dir in _windowsDependencyDirs)
|
||||||
{
|
{
|
||||||
string dirPath = Path.Combine(HomeDir, dir);
|
string dirPath = Path.Combine(_homeDir, dir);
|
||||||
if (Directory.Exists(dirPath))
|
if (Directory.Exists(dirPath))
|
||||||
{
|
{
|
||||||
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
||||||
@@ -798,7 +790,7 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
public static void CleanupUpdate()
|
public static void CleanupUpdate()
|
||||||
{
|
{
|
||||||
foreach (string file in Directory.GetFiles(HomeDir, "*.ryuold", SearchOption.AllDirectories))
|
foreach (string file in Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ namespace Ryujinx.Ava
|
|||||||
[LibraryImport("user32.dll", SetLastError = true)]
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
private const uint MbIconwarning = 0x30;
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
@@ -39,7 +39,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||||
{
|
{
|
||||||
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreviewerDetached = true;
|
PreviewerDetached = true;
|
||||||
@@ -59,15 +59,12 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
EnableIme = true,
|
EnableIme = true,
|
||||||
UseEGL = false,
|
RenderingMode = new[] { X11RenderingMode.Glx, X11RenderingMode.Software },
|
||||||
UseGpu = true
|
|
||||||
})
|
})
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
EnableMultitouch = true,
|
WinUICompositionBackdropCornerRadius = 8.0f,
|
||||||
UseWgl = false,
|
RenderingMode = new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software },
|
||||||
AllowEglInitialization = false,
|
|
||||||
CompositionBackdropCornerRadius = 8.0f,
|
|
||||||
})
|
})
|
||||||
.UseSkia();
|
.UseSkia();
|
||||||
}
|
}
|
||||||
@@ -103,8 +100,6 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
ReloadConfig();
|
ReloadConfig();
|
||||||
|
|
||||||
ForceDpiAware.Windows();
|
|
||||||
|
|
||||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||||
|
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
@@ -192,7 +187,7 @@ namespace Ryujinx.Ava
|
|||||||
"never" => HideCursorMode.Never,
|
"never" => HideCursorMode.Never,
|
||||||
"onidle" => HideCursorMode.OnIdle,
|
"onidle" => HideCursorMode.OnIdle,
|
||||||
"always" => HideCursorMode.Always,
|
"always" => HideCursorMode.Always,
|
||||||
_ => ConfigurationState.Instance.HideCursor.Value
|
_ => ConfigurationState.Instance.HideCursor.Value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
<RootNamespace>Ryujinx.Ava</RootNamespace>
|
<RootNamespace>Ryujinx.Ava</RootNamespace>
|
||||||
<ApplicationIcon>Ryujinx.ico</ApplicationIcon>
|
<ApplicationIcon>Ryujinx.ico</ApplicationIcon>
|
||||||
<TieredPGO>true</TieredPGO>
|
<TieredPGO>true</TieredPGO>
|
||||||
|
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||||
@@ -26,7 +28,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" />
|
<PackageReference Include="Avalonia" />
|
||||||
<PackageReference Include="Avalonia.Desktop" />
|
<PackageReference Include="Avalonia.Desktop" />
|
||||||
<PackageReference Include="Avalonia.Diagnostics" />
|
<PackageReference Include="Avalonia.Diagnostics" Condition="'$(Configuration)'=='Debug'" />
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" />
|
||||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
|
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
|
||||||
<PackageReference Include="Avalonia.Svg" />
|
<PackageReference Include="Avalonia.Svg" />
|
||||||
@@ -34,7 +36,6 @@
|
|||||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" />
|
<PackageReference Include="jp2masa.Avalonia.Flexbox" />
|
||||||
<PackageReference Include="DynamicData" />
|
<PackageReference Include="DynamicData" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" />
|
<PackageReference Include="FluentAvaloniaUI" />
|
||||||
<PackageReference Include="XamlNameReferenceGenerator" />
|
|
||||||
|
|
||||||
<PackageReference Include="OpenTK.Core" />
|
<PackageReference Include="OpenTK.Core" />
|
||||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||||
@@ -97,10 +98,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</AvaloniaResource>
|
</AvaloniaResource>
|
||||||
<AvaloniaResource Include="Assets\Fonts\SegoeFluentIcons.ttf" />
|
<AvaloniaResource Include="Assets\Fonts\SegoeFluentIcons.ttf" />
|
||||||
<AvaloniaResource Include="Assets\Styles\BaseLight.xaml">
|
<AvaloniaResource Include="Assets\Styles\Themes.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
</AvaloniaResource>
|
|
||||||
<AvaloniaResource Include="Assets\Styles\BaseDark.xaml">
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</AvaloniaResource>
|
</AvaloniaResource>
|
||||||
<AvaloniaResource Include="Assets\Styles\Styles.xaml" />
|
<AvaloniaResource Include="Assets\Styles\Styles.xaml" />
|
||||||
@@ -123,8 +121,7 @@
|
|||||||
<None Remove="Assets\Locales\zh_CN.json" />
|
<None Remove="Assets\Locales\zh_CN.json" />
|
||||||
<None Remove="Assets\Locales\zh_TW.json" />
|
<None Remove="Assets\Locales\zh_TW.json" />
|
||||||
<None Remove="Assets\Styles\Styles.xaml" />
|
<None Remove="Assets\Styles\Styles.xaml" />
|
||||||
<None Remove="Assets\Styles\BaseDark.xaml" />
|
<None Remove="Assets\Styles\Themes.xaml" />
|
||||||
<None Remove="Assets\Styles\BaseLight.xaml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -53,8 +53,6 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
|
|
||||||
bool opened = false;
|
bool opened = false;
|
||||||
|
|
||||||
_parent.Activate();
|
|
||||||
|
|
||||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
@@ -64,7 +62,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
|
LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
|
||||||
(int)Symbol.Important,
|
(int)Symbol.Important,
|
||||||
deferEvent,
|
deferEvent,
|
||||||
async (window) =>
|
async window =>
|
||||||
{
|
{
|
||||||
if (opened)
|
if (opened)
|
||||||
{
|
{
|
||||||
@@ -112,7 +110,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
|
var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
|
||||||
|
|
||||||
if (response.Result == UserResult.Ok)
|
if (response.Result == UserResult.Ok)
|
||||||
{
|
{
|
||||||
@@ -142,10 +140,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
|
||||||
{
|
{
|
||||||
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
|
device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
|
||||||
if (_parent.ViewModel.AppHost != null)
|
_parent.ViewModel.AppHost?.Stop();
|
||||||
{
|
|
||||||
_parent.ViewModel.AppHost.Stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
||||||
@@ -162,7 +157,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
{
|
{
|
||||||
Title = title,
|
Title = title,
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterScreen,
|
WindowStartupLocation = WindowStartupLocation.CenterScreen,
|
||||||
Width = 400
|
Width = 400,
|
||||||
};
|
};
|
||||||
|
|
||||||
object response = await msgDialog.Run();
|
object response = await msgDialog.Run();
|
||||||
|
@@ -3,13 +3,11 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.HLE.Ui;
|
using Ryujinx.HLE.Ui;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using HidKey = Ryujinx.Common.Configuration.Hid.Key;
|
using HidKey = Ryujinx.Common.Configuration.Hid.Key;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Applet
|
namespace Ryujinx.Ava.UI.Applet
|
||||||
@@ -17,7 +15,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler
|
class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler
|
||||||
{
|
{
|
||||||
private MainWindow _parent;
|
private MainWindow _parent;
|
||||||
private OffscreenTextBox _hiddenTextBox;
|
private readonly OffscreenTextBox _hiddenTextBox;
|
||||||
private bool _canProcessInput;
|
private bool _canProcessInput;
|
||||||
private IDisposable _textChangedSubscription;
|
private IDisposable _textChangedSubscription;
|
||||||
private IDisposable _selectionStartChangedSubscription;
|
private IDisposable _selectionStartChangedSubscription;
|
||||||
@@ -76,7 +74,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.RoutedEvent = _hiddenTextBox.GetKeyUpRoutedEvent();
|
e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
@@ -96,7 +94,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.RoutedEvent = _hiddenTextBox.GetKeyUpRoutedEvent();
|
e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent();
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
|
@@ -9,7 +9,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
{
|
{
|
||||||
public AvaloniaHostUiTheme(MainWindow parent)
|
public AvaloniaHostUiTheme(MainWindow parent)
|
||||||
{
|
{
|
||||||
FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000, 0) ? "Segoe UI Variable" : parent.FontFamily.Name;
|
FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) ? "Segoe UI Variable" : parent.FontFamily.Name;
|
||||||
DefaultBackgroundColor = BrushToThemeColor(parent.Background);
|
DefaultBackgroundColor = BrushToThemeColor(parent.Background);
|
||||||
DefaultForegroundColor = BrushToThemeColor(parent.Foreground);
|
DefaultForegroundColor = BrushToThemeColor(parent.Foreground);
|
||||||
DefaultBorderColor = BrushToThemeColor(parent.BorderBrush);
|
DefaultBorderColor = BrushToThemeColor(parent.BorderBrush);
|
||||||
@@ -25,7 +25,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
public ThemeColor SelectionBackgroundColor { get; }
|
public ThemeColor SelectionBackgroundColor { get; }
|
||||||
public ThemeColor SelectionForegroundColor { get; }
|
public ThemeColor SelectionForegroundColor { get; }
|
||||||
|
|
||||||
private ThemeColor BrushToThemeColor(IBrush brush)
|
private static ThemeColor BrushToThemeColor(IBrush brush)
|
||||||
{
|
{
|
||||||
if (brush is SolidColorBrush solidColor)
|
if (brush is SolidColorBrush solidColor)
|
||||||
{
|
{
|
||||||
@@ -34,10 +34,8 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
(float)solidColor.Color.G / 255,
|
(float)solidColor.Color.G / 255,
|
||||||
(float)solidColor.Color.B / 255);
|
(float)solidColor.Color.B / 255);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return new ThemeColor();
|
return new ThemeColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Text="{Binding Message}"
|
Text="{ReflectionBinding Message}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Name="ButtonStack"
|
Name="ButtonStack"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
@@ -19,9 +18,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
Message = message;
|
Message = message;
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
#if DEBUG
|
|
||||||
this.AttachDevTools();
|
|
||||||
#endif
|
|
||||||
int responseId = 0;
|
int responseId = 0;
|
||||||
|
|
||||||
if (buttons != null)
|
if (buttons != null)
|
||||||
@@ -42,9 +39,6 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
{
|
{
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
#if DEBUG
|
|
||||||
this.AttachDevTools();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
@@ -34,13 +34,13 @@
|
|||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
Text="{Binding MainText}"
|
Text="{ReflectionBinding MainText}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
Text="{Binding SecondaryText}"
|
Text="{ReflectionBinding SecondaryText}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="Input"
|
Name="Input"
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Focusable="True"
|
Focusable="True"
|
||||||
KeyUp="Message_KeyUp"
|
KeyUp="Message_KeyUp"
|
||||||
Text="{Binding Message}"
|
Text="{ReflectionBinding Message}"
|
||||||
TextInput="Message_TextInput"
|
TextInput="Message_TextInput"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
UseFloatingWatermark="True" />
|
UseFloatingWatermark="True" />
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using FluentAvalonia.Core;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using System;
|
using System;
|
||||||
@@ -22,7 +19,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
private Predicate<string> _checkInput = _ => true;
|
private Predicate<string> _checkInput = _ => true;
|
||||||
private int _inputMax;
|
private int _inputMax;
|
||||||
private int _inputMin;
|
private int _inputMin;
|
||||||
private string _placeholder;
|
private readonly string _placeholder;
|
||||||
|
|
||||||
private ContentDialog _host;
|
private ContentDialog _host;
|
||||||
|
|
||||||
@@ -57,13 +54,13 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
public string MainText { get; set; } = "";
|
public string MainText { get; set; } = "";
|
||||||
public string SecondaryText { get; set; } = "";
|
public string SecondaryText { get; set; } = "";
|
||||||
|
|
||||||
public static async Task<(UserResult Result, string Input)> ShowInputDialog(StyleableWindow window, string title, SoftwareKeyboardUiArgs args)
|
public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, SoftwareKeyboardUiArgs args)
|
||||||
{
|
{
|
||||||
ContentDialog contentDialog = new ContentDialog();
|
ContentDialog contentDialog = new();
|
||||||
|
|
||||||
UserResult result = UserResult.Cancel;
|
UserResult result = UserResult.Cancel;
|
||||||
|
|
||||||
SwkbdAppletDialog content = new SwkbdAppletDialog(args.HeaderText, args.SubtitleText, args.GuideText, args.InitialText);
|
SwkbdAppletDialog content = new(args.HeaderText, args.SubtitleText, args.GuideText, args.InitialText);
|
||||||
|
|
||||||
string input = string.Empty;
|
string input = string.Empty;
|
||||||
|
|
||||||
@@ -78,15 +75,16 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel];
|
contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel];
|
||||||
contentDialog.Content = content;
|
contentDialog.Content = content;
|
||||||
|
|
||||||
TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) =>
|
void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (eventArgs.Result == ContentDialogResult.Primary)
|
if (eventArgs.Result == ContentDialogResult.Primary)
|
||||||
{
|
{
|
||||||
result = UserResult.Ok;
|
result = UserResult.Ok;
|
||||||
input = content.Input.Text;
|
input = content.Input.Text;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
contentDialog.Closed += handler;
|
|
||||||
|
contentDialog.Closed += Handler;
|
||||||
|
|
||||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||||
|
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
x:Class="Ryujinx.Ava.UI.Controls.ApplicationContextMenu"
|
x:Class="Ryujinx.Ava.UI.Controls.ApplicationContextMenu"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale">
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Click="RunApplication_Click"
|
Click="RunApplication_Click"
|
||||||
Header="{locale:Locale GameListContextMenuRunApplication}" />
|
Header="{locale:Locale GameListContextMenuRunApplication}" />
|
||||||
|
@@ -18,7 +18,6 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
using UserId = LibHac.Fs.UserId;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Controls
|
namespace Ryujinx.Ava.UI.Controls
|
||||||
{
|
{
|
||||||
@@ -53,7 +52,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
|
public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if ((sender as MenuItem)?.DataContext is MainWindowViewModel viewModel)
|
if (sender is MenuItem { DataContext: MainWindowViewModel viewModel })
|
||||||
{
|
{
|
||||||
OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
|
OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
|
||||||
}
|
}
|
||||||
@@ -300,7 +299,11 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
if (viewModel?.SelectedApplication != null)
|
if (viewModel?.SelectedApplication != null)
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Code, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
|
await ApplicationHelper.ExtractSection(
|
||||||
|
viewModel.StorageProvider,
|
||||||
|
NcaSectionType.Code,
|
||||||
|
viewModel.SelectedApplication.Path,
|
||||||
|
viewModel.SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +313,11 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
if (viewModel?.SelectedApplication != null)
|
if (viewModel?.SelectedApplication != null)
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Data, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
|
await ApplicationHelper.ExtractSection(
|
||||||
|
viewModel.StorageProvider,
|
||||||
|
NcaSectionType.Data,
|
||||||
|
viewModel.SelectedApplication.Path,
|
||||||
|
viewModel.SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +327,11 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
if (viewModel?.SelectedApplication != null)
|
if (viewModel?.SelectedApplication != null)
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Logo, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
|
await ApplicationHelper.ExtractSection(
|
||||||
|
viewModel.StorageProvider,
|
||||||
|
NcaSectionType.Logo,
|
||||||
|
viewModel.SelectedApplication.Path,
|
||||||
|
viewModel.SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,7 +11,9 @@
|
|||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
Focusable="True"
|
Focusable="True"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
|
<controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
|
||||||
@@ -27,7 +29,7 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
ContextFlyout="{StaticResource ApplicationContextMenu}"
|
ContextFlyout="{StaticResource ApplicationContextMenu}"
|
||||||
DoubleTapped="GameList_DoubleTapped"
|
DoubleTapped="GameList_DoubleTapped"
|
||||||
Items="{Binding AppsObservableList}"
|
ItemsSource="{Binding AppsObservableList}"
|
||||||
SelectionChanged="GameList_SelectionChanged">
|
SelectionChanged="GameList_SelectionChanged">
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
@@ -43,8 +45,8 @@
|
|||||||
<Setter Property="Margin" Value="5" />
|
<Setter Property="Margin" Value="5" />
|
||||||
<Setter Property="CornerRadius" Value="4" />
|
<Setter Property="CornerRadius" Value="4" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
|
||||||
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
|
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.GridItemSelectorSize}" />
|
||||||
</Style>
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@@ -54,10 +56,10 @@
|
|||||||
Margin="10"
|
Margin="10"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
CornerRadius="4">
|
CornerRadius="4">
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -76,9 +78,9 @@
|
|||||||
Margin="0,10,0,0"
|
Margin="0,10,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
IsVisible="{ReflectionBinding $parent[UserControl].DataContext.ShowNames}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{Binding TitleName}"
|
Text="{Binding TitleName}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
@@ -25,12 +24,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
public void GameList_DoubleTapped(object sender, TappedEventArgs args)
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
|
||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
Focusable="True"
|
Focusable="True"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
x:DataType="viewModels:MainWindowViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
|
<controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
|
||||||
@@ -27,7 +29,7 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
ContextFlyout="{StaticResource ApplicationContextMenu}"
|
ContextFlyout="{StaticResource ApplicationContextMenu}"
|
||||||
DoubleTapped="GameList_DoubleTapped"
|
DoubleTapped="GameList_DoubleTapped"
|
||||||
Items="{Binding AppsObservableList}"
|
ItemsSource="{Binding AppsObservableList}"
|
||||||
SelectionChanged="GameList_SelectionChanged">
|
SelectionChanged="GameList_SelectionChanged">
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
@@ -39,8 +41,8 @@
|
|||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ListBox.ItemsPanel>
|
</ListBox.ItemsPanel>
|
||||||
<ListBox.Styles>
|
<ListBox.Styles>
|
||||||
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
|
||||||
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.ListItemSelectorSize}" />
|
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.ListItemSelectorSize}" />
|
||||||
</Style>
|
</Style>
|
||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@@ -65,10 +67,10 @@
|
|||||||
Grid.RowSpan="3"
|
Grid.RowSpan="3"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
|
||||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
|
||||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
|
||||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
|
||||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||||
<Border
|
<Border
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
@@ -25,12 +24,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
public void GameList_DoubleTapped(object sender, TappedEventArgs args)
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
|
||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,6 @@ using Avalonia;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.Core;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
@@ -10,7 +9,6 @@ using LibHac.Fs;
|
|||||||
using LibHac.Fs.Shim;
|
using LibHac.Fs.Shim;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ava.UI.Views.User;
|
using Ryujinx.Ava.UI.Views.User;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
@@ -19,6 +17,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
||||||
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Controls
|
namespace Ryujinx.Ava.UI.Controls
|
||||||
@@ -56,7 +55,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoBack(object parameter = null)
|
public void GoBack()
|
||||||
{
|
{
|
||||||
if (ContentFrame.BackStack.Count > 0)
|
if (ContentFrame.BackStack.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -75,14 +74,14 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
|
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
|
||||||
{
|
{
|
||||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||||
ContentDialog contentDialog = new ContentDialog
|
ContentDialog contentDialog = new()
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
||||||
PrimaryButtonText = "",
|
PrimaryButtonText = "",
|
||||||
SecondaryButtonText = "",
|
SecondaryButtonText = "",
|
||||||
CloseButtonText = "",
|
CloseButtonText = "",
|
||||||
Content = content,
|
Content = content,
|
||||||
Padding = new Thickness(0)
|
Padding = new Thickness(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
contentDialog.Closed += (sender, args) =>
|
contentDialog.Closed += (sender, args) =>
|
||||||
@@ -125,7 +124,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
||||||
|
|
||||||
HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new();
|
HashSet<UserId> lostAccounts = new();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -139,7 +138,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
for (int i = 0; i < readCount; i++)
|
for (int i = 0; i < readCount; i++)
|
||||||
{
|
{
|
||||||
var save = saveDataInfo[i];
|
var save = saveDataInfo[i];
|
||||||
var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
|
var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
|
||||||
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
|
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
|
||||||
{
|
{
|
||||||
lostAccounts.Add(id);
|
lostAccounts.Add(id);
|
||||||
@@ -166,7 +165,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
|
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
{
|
{
|
||||||
async void Action()
|
static async void Action()
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Layout;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.Core;
|
using FluentAvalonia.Core;
|
||||||
@@ -36,13 +37,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
PrimaryButtonText = primaryButton,
|
PrimaryButtonText = primaryButton,
|
||||||
SecondaryButtonText = secondaryButton,
|
SecondaryButtonText = secondaryButton,
|
||||||
CloseButtonText = closeButton,
|
CloseButtonText = closeButton,
|
||||||
Content = content
|
Content = content,
|
||||||
};
|
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||||
|
|
||||||
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
|
|
||||||
{
|
{
|
||||||
result = primaryButtonResult;
|
result = primaryButtonResult;
|
||||||
});
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
||||||
{
|
{
|
||||||
@@ -96,7 +96,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
Func<Window, Task> doWhileDeferred = null)
|
Func<Window, Task> doWhileDeferred = null)
|
||||||
{
|
{
|
||||||
bool startedDeferring = false;
|
bool startedDeferring = false;
|
||||||
UserResult result = UserResult.None;
|
|
||||||
|
|
||||||
return await ShowTextDialog(
|
return await ShowTextDialog(
|
||||||
title,
|
title,
|
||||||
@@ -123,8 +122,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
var deferral = args.GetDeferral();
|
var deferral = args.GetDeferral();
|
||||||
|
|
||||||
result = primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok;
|
|
||||||
|
|
||||||
sender.PrimaryButtonClick -= DeferClose;
|
sender.PrimaryButtonClick -= DeferClose;
|
||||||
|
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(() =>
|
||||||
@@ -150,10 +147,10 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
Grid content = new()
|
Grid content = new()
|
||||||
{
|
{
|
||||||
RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() },
|
RowDefinitions = new RowDefinitions { new(), new() },
|
||||||
ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() },
|
ColumnDefinitions = new ColumnDefinitions { new(GridLength.Auto), new() },
|
||||||
|
|
||||||
MinHeight = 80
|
MinHeight = 80,
|
||||||
};
|
};
|
||||||
|
|
||||||
SymbolIcon icon = new()
|
SymbolIcon icon = new()
|
||||||
@@ -161,7 +158,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
Symbol = (Symbol)symbol,
|
Symbol = (Symbol)symbol,
|
||||||
Margin = new Thickness(10),
|
Margin = new Thickness(10),
|
||||||
FontSize = 40,
|
FontSize = 40,
|
||||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.SetColumn(icon, 0);
|
Grid.SetColumn(icon, 0);
|
||||||
@@ -173,7 +170,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
Text = primaryText,
|
Text = primaryText,
|
||||||
Margin = new Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450,
|
||||||
};
|
};
|
||||||
|
|
||||||
TextBlock secondaryLabel = new()
|
TextBlock secondaryLabel = new()
|
||||||
@@ -181,7 +178,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
Text = secondaryText,
|
Text = secondaryText,
|
||||||
Margin = new Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450,
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid.SetColumn(primaryLabel, 1);
|
Grid.SetColumn(primaryLabel, 1);
|
||||||
@@ -318,14 +315,16 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
Window parent = GetMainWindow();
|
Window parent = GetMainWindow();
|
||||||
|
|
||||||
if (parent != null && parent.IsActive && (parent as MainWindow).ViewModel.IsGameRunning)
|
if (parent is MainWindow window)
|
||||||
{
|
{
|
||||||
|
parent.Activate();
|
||||||
|
|
||||||
contentDialogOverlayWindow = new()
|
contentDialogOverlayWindow = new()
|
||||||
{
|
{
|
||||||
Height = parent.Bounds.Height,
|
Height = parent.Bounds.Height,
|
||||||
Width = parent.Bounds.Width,
|
Width = parent.Bounds.Width,
|
||||||
Position = parent.PointToScreen(new Point()),
|
Position = parent.PointToScreen(new Point()),
|
||||||
ShowInTaskbar = false
|
ShowInTaskbar = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
parent.PositionChanged += OverlayOnPositionChanged;
|
parent.PositionChanged += OverlayOnPositionChanged;
|
||||||
@@ -372,7 +371,9 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = await contentDialog.ShowAsync();
|
result = ContentDialogResult.None;
|
||||||
|
|
||||||
|
Logger.Warning?.Print(LogClass.Ui, "Content dialog overlay failed to populate. Default value has been returned.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -389,11 +390,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
private static Window GetMainWindow()
|
private static Window GetMainWindow()
|
||||||
{
|
{
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
|
||||||
{
|
{
|
||||||
foreach (Window item in al.Windows)
|
foreach (Window item in al.Windows)
|
||||||
{
|
{
|
||||||
if (item.IsActive && item is MainWindow window)
|
if (item is MainWindow window)
|
||||||
{
|
{
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
{
|
{
|
||||||
List,
|
List,
|
||||||
Grid,
|
Grid,
|
||||||
Chip
|
Chip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
using Avalonia.Data;
|
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using System;
|
using System;
|
||||||
@@ -8,13 +7,13 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
public class GlyphValueConverter : MarkupExtension
|
public class GlyphValueConverter : MarkupExtension
|
||||||
{
|
{
|
||||||
private string _key;
|
private readonly string _key;
|
||||||
|
|
||||||
private static Dictionary<Glyph, string> _glyphs = new Dictionary<Glyph, string>
|
private static readonly Dictionary<Glyph, string> _glyphs = new()
|
||||||
{
|
{
|
||||||
{ Glyph.List, char.ConvertFromUtf32((int)Symbol.List).ToString() },
|
{ Glyph.List, char.ConvertFromUtf32((int)Symbol.List) },
|
||||||
{ Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll).ToString() },
|
{ Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll) },
|
||||||
{ Glyph.Chip, char.ConvertFromUtf32(59748).ToString() }
|
{ Glyph.Chip, char.ConvertFromUtf32(59748) },
|
||||||
};
|
};
|
||||||
|
|
||||||
public GlyphValueConverter(string key)
|
public GlyphValueConverter(string key)
|
||||||
@@ -37,13 +36,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension binding = new($"[{_key}]")
|
return this[_key];
|
||||||
{
|
|
||||||
Mode = BindingMode.OneWay,
|
|
||||||
Source = this
|
|
||||||
};
|
|
||||||
|
|
||||||
return binding.ProvideValue(serviceProvider);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,52 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using System;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Helpers
|
|
||||||
{
|
|
||||||
public class HotKeyControl : ContentControl, ICommandSource
|
|
||||||
{
|
|
||||||
public static readonly StyledProperty<object> CommandParameterProperty =
|
|
||||||
AvaloniaProperty.Register<HotKeyControl, object>(nameof(CommandParameter));
|
|
||||||
|
|
||||||
public static readonly DirectProperty<HotKeyControl, ICommand> CommandProperty =
|
|
||||||
AvaloniaProperty.RegisterDirect<HotKeyControl, ICommand>(nameof(Command),
|
|
||||||
control => control.Command, (control, command) => control.Command = command, enableDataValidation: true);
|
|
||||||
|
|
||||||
public static readonly StyledProperty<KeyGesture> HotKeyProperty = HotKeyManager.HotKeyProperty.AddOwner<Button>();
|
|
||||||
|
|
||||||
private ICommand _command;
|
|
||||||
private bool _commandCanExecute;
|
|
||||||
|
|
||||||
public ICommand Command
|
|
||||||
{
|
|
||||||
get { return _command; }
|
|
||||||
set { SetAndRaise(CommandProperty, ref _command, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyGesture HotKey
|
|
||||||
{
|
|
||||||
get { return GetValue(HotKeyProperty); }
|
|
||||||
set { SetValue(HotKeyProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public object CommandParameter
|
|
||||||
{
|
|
||||||
get { return GetValue(CommandParameterProperty); }
|
|
||||||
set { SetValue(CommandParameterProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CanExecuteChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var canExecute = Command == null || Command.CanExecute(CommandParameter);
|
|
||||||
|
|
||||||
if (canExecute != _commandCanExecute)
|
|
||||||
{
|
|
||||||
_commandCanExecute = canExecute;
|
|
||||||
UpdateIsEffectivelyEnabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,15 +1,17 @@
|
|||||||
|
using Avalonia.Logging;
|
||||||
using Avalonia.Utilities;
|
using Avalonia.Utilities;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Helpers
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
{
|
{
|
||||||
using AvaLogger = Avalonia.Logging.Logger;
|
using AvaLogger = Avalonia.Logging.Logger;
|
||||||
using AvaLogLevel = Avalonia.Logging.LogEventLevel;
|
using AvaLogLevel = LogEventLevel;
|
||||||
using RyuLogClass = Ryujinx.Common.Logging.LogClass;
|
using RyuLogClass = LogClass;
|
||||||
using RyuLogger = Ryujinx.Common.Logging.Logger;
|
using RyuLogger = Ryujinx.Common.Logging.Logger;
|
||||||
|
|
||||||
internal class LoggerAdapter : Avalonia.Logging.ILogSink
|
internal class LoggerAdapter : ILogSink
|
||||||
{
|
{
|
||||||
public static void Register()
|
public static void Register()
|
||||||
{
|
{
|
||||||
@@ -26,7 +28,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
AvaLogLevel.Warning => RyuLogger.Debug,
|
AvaLogLevel.Warning => RyuLogger.Debug,
|
||||||
AvaLogLevel.Error => RyuLogger.Error,
|
AvaLogLevel.Error => RyuLogger.Error,
|
||||||
AvaLogLevel.Fatal => RyuLogger.Error,
|
AvaLogLevel.Fatal => RyuLogger.Error,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,21 +42,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, null));
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log<T0>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0)
|
|
||||||
{
|
|
||||||
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, new object[] { propertyValue0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log<T0, T1>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
|
|
||||||
{
|
|
||||||
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, new object[] { propertyValue0, propertyValue1 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log<T0, T1, T2>(AvaLogLevel level, string area, object source, string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
|
|
||||||
{
|
|
||||||
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, new object[] { propertyValue0, propertyValue1, propertyValue2 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues)
|
public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues)
|
||||||
{
|
{
|
||||||
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, propertyValues));
|
GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, propertyValues));
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
private readonly Action<T> _callback;
|
private readonly Action<T> _callback;
|
||||||
private bool _busy;
|
private bool _busy;
|
||||||
private Func<T, Task> _asyncCallback;
|
private readonly Func<T, Task> _asyncCallback;
|
||||||
|
|
||||||
public MiniCommand(Action<T> callback)
|
public MiniCommand(Action<T> callback)
|
||||||
{
|
{
|
||||||
|
@@ -25,7 +25,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
Position = NotificationPosition.BottomRight,
|
Position = NotificationPosition.BottomRight,
|
||||||
MaxItems = MaxNotifications,
|
MaxItems = MaxNotifications,
|
||||||
Margin = new Thickness(0, 0, 15, 40)
|
Margin = new Thickness(0, 0, 15, 40),
|
||||||
};
|
};
|
||||||
|
|
||||||
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
|
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
|
||||||
|
@@ -6,12 +6,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
public class OffscreenTextBox : TextBox
|
public class OffscreenTextBox : TextBox
|
||||||
{
|
{
|
||||||
public RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent()
|
public static RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent()
|
||||||
{
|
{
|
||||||
return KeyDownEvent;
|
return KeyDownEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent()
|
public static RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent()
|
||||||
{
|
{
|
||||||
return KeyUpEvent;
|
return KeyUpEvent;
|
||||||
}
|
}
|
||||||
@@ -28,12 +28,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
public void SendText(string text)
|
public void SendText(string text)
|
||||||
{
|
{
|
||||||
OnTextInput(new TextInputEventArgs()
|
OnTextInput(new TextInputEventArgs
|
||||||
{
|
{
|
||||||
Text = text,
|
Text = text,
|
||||||
Device = KeyboardDevice.Instance,
|
|
||||||
Source = this,
|
Source = this,
|
||||||
RoutedEvent = TextInputEvent
|
RoutedEvent = TextInputEvent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs
Normal file
28
src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
internal class TimeZoneConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public static TimeZoneConverter Instance = new();
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeZone = (TimeZone)value;
|
||||||
|
return string.Format("{0} {1} {2}", timeZone.UtcDifference, timeZone.Location, timeZone.Abbreviation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -24,7 +23,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed],
|
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed],
|
||||||
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound],
|
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound],
|
||||||
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown],
|
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown],
|
||||||
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined]
|
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription],
|
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription],
|
||||||
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription],
|
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription],
|
||||||
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription],
|
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription],
|
||||||
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription]
|
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
UserError.NoKeys or
|
UserError.NoKeys or
|
||||||
UserError.NoFirmware or
|
UserError.NoFirmware or
|
||||||
UserError.FirmwareParsingFailed => true,
|
UserError.FirmwareParsingFailed => true,
|
||||||
_ => false
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,11 +62,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
{
|
{
|
||||||
UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
|
UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
|
||||||
UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
|
UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
|
||||||
_ => SetupGuideUrl
|
_ => SetupGuideUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ShowUserErrorDialog(UserError error, StyleableWindow owner)
|
public static async Task ShowUserErrorDialog(UserError error)
|
||||||
{
|
{
|
||||||
string errorCode = GetErrorCode(error);
|
string errorCode = GetErrorCode(error);
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
@@ -10,46 +11,47 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
[Flags]
|
[Flags]
|
||||||
public enum ClassStyles : uint
|
public enum ClassStyles : uint
|
||||||
{
|
{
|
||||||
CS_CLASSDC = 0x40,
|
CsClassdc = 0x40,
|
||||||
CS_OWNDC = 0x20,
|
CsOwndc = 0x20,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum WindowStyles : uint
|
public enum WindowStyles : uint
|
||||||
{
|
{
|
||||||
WS_CHILD = 0x40000000
|
WsChild = 0x40000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Cursors : uint
|
public enum Cursors : uint
|
||||||
{
|
{
|
||||||
IDC_ARROW = 32512
|
IdcArrow = 32512,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
|
||||||
public enum WindowsMessages : uint
|
public enum WindowsMessages : uint
|
||||||
{
|
{
|
||||||
MOUSEMOVE = 0x0200,
|
Mousemove = 0x0200,
|
||||||
LBUTTONDOWN = 0x0201,
|
Lbuttondown = 0x0201,
|
||||||
LBUTTONUP = 0x0202,
|
Lbuttonup = 0x0202,
|
||||||
LBUTTONDBLCLK = 0x0203,
|
Lbuttondblclk = 0x0203,
|
||||||
RBUTTONDOWN = 0x0204,
|
Rbuttondown = 0x0204,
|
||||||
RBUTTONUP = 0x0205,
|
Rbuttonup = 0x0205,
|
||||||
RBUTTONDBLCLK = 0x0206,
|
Rbuttondblclk = 0x0206,
|
||||||
MBUTTONDOWN = 0x0207,
|
Mbuttondown = 0x0207,
|
||||||
MBUTTONUP = 0x0208,
|
Mbuttonup = 0x0208,
|
||||||
MBUTTONDBLCLK = 0x0209,
|
Mbuttondblclk = 0x0209,
|
||||||
MOUSEWHEEL = 0x020A,
|
Mousewheel = 0x020A,
|
||||||
XBUTTONDOWN = 0x020B,
|
Xbuttondown = 0x020B,
|
||||||
XBUTTONUP = 0x020C,
|
Xbuttonup = 0x020C,
|
||||||
XBUTTONDBLCLK = 0x020D,
|
Xbuttondblclk = 0x020D,
|
||||||
MOUSEHWHEEL = 0x020E,
|
Mousehwheel = 0x020E,
|
||||||
MOUSELAST = 0x020E
|
Mouselast = 0x020E,
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||||
internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
|
internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct WNDCLASSEX
|
public struct WndClassEx
|
||||||
{
|
{
|
||||||
public int cbSize;
|
public int cbSize;
|
||||||
public ClassStyles style;
|
public ClassStyles style;
|
||||||
@@ -64,9 +66,9 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
public IntPtr lpszClassName;
|
public IntPtr lpszClassName;
|
||||||
public IntPtr hIconSm;
|
public IntPtr hIconSm;
|
||||||
|
|
||||||
public WNDCLASSEX()
|
public WndClassEx()
|
||||||
{
|
{
|
||||||
cbSize = Marshal.SizeOf<WNDCLASSEX>();
|
cbSize = Marshal.SizeOf<WndClassEx>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,17 +79,17 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
|
|
||||||
public static IntPtr CreateArrowCursor()
|
public static IntPtr CreateArrowCursor()
|
||||||
{
|
{
|
||||||
return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW);
|
return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IdcArrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport("user32.dll")]
|
[LibraryImport("user32.dll")]
|
||||||
public static partial IntPtr SetCursor(IntPtr handle);
|
public static partial IntPtr SetCursor(IntPtr handle);
|
||||||
|
|
||||||
[LibraryImport("user32.dll")]
|
[LibraryImport("user32.dll")]
|
||||||
public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, byte[] pvANDPlane, byte[] pvXORPlane);
|
public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, byte[] pvAndPlane, byte[] pvXorPlane);
|
||||||
|
|
||||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
|
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
|
||||||
public static partial ushort RegisterClassEx(ref WNDCLASSEX param);
|
public static partial ushort RegisterClassEx(ref WndClassEx param);
|
||||||
|
|
||||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")]
|
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")]
|
||||||
public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
|
public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
|
||||||
|
@@ -35,6 +35,6 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string CleanName => Name.Substring(1, Name.Length - 8);
|
public string CleanName => Name[1..^7];
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,6 +4,6 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Controller
|
Controller,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,16 +7,16 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Models
|
namespace Ryujinx.Ava.UI.Models
|
||||||
{
|
{
|
||||||
internal class InputConfiguration<Key, Stick> : BaseModel
|
internal class InputConfiguration<TKey, TStick> : BaseModel
|
||||||
{
|
{
|
||||||
private float _deadzoneRight;
|
private float _deadzoneRight;
|
||||||
private float _triggerThreshold;
|
private float _triggerThreshold;
|
||||||
private float _deadzoneLeft;
|
private float _deadzoneLeft;
|
||||||
private double _gyroDeadzone;
|
private double _gyroDeadzone;
|
||||||
private int _sensitivity;
|
private int _sensitivity;
|
||||||
private bool enableMotion;
|
private bool _enableMotion;
|
||||||
private float weakRumble;
|
private float _weakRumble;
|
||||||
private float strongRumble;
|
private float _strongRumble;
|
||||||
private float _rangeLeft;
|
private float _rangeLeft;
|
||||||
private float _rangeRight;
|
private float _rangeRight;
|
||||||
|
|
||||||
@@ -37,17 +37,17 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerIndex PlayerIndex { get; set; }
|
public PlayerIndex PlayerIndex { get; set; }
|
||||||
|
|
||||||
public Stick LeftJoystick { get; set; }
|
public TStick LeftJoystick { get; set; }
|
||||||
public bool LeftInvertStickX { get; set; }
|
public bool LeftInvertStickX { get; set; }
|
||||||
public bool LeftInvertStickY { get; set; }
|
public bool LeftInvertStickY { get; set; }
|
||||||
public bool RightRotate90 { get; set; }
|
public bool RightRotate90 { get; set; }
|
||||||
public Key LeftControllerStickButton { get; set; }
|
public TKey LeftControllerStickButton { get; set; }
|
||||||
|
|
||||||
public Stick RightJoystick { get; set; }
|
public TStick RightJoystick { get; set; }
|
||||||
public bool RightInvertStickX { get; set; }
|
public bool RightInvertStickX { get; set; }
|
||||||
public bool RightInvertStickY { get; set; }
|
public bool RightInvertStickY { get; set; }
|
||||||
public bool LeftRotate90 { get; set; }
|
public bool LeftRotate90 { get; set; }
|
||||||
public Key RightControllerStickButton { get; set; }
|
public TKey RightControllerStickButton { get; set; }
|
||||||
|
|
||||||
public float DeadzoneLeft
|
public float DeadzoneLeft
|
||||||
{
|
{
|
||||||
@@ -106,38 +106,37 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
public MotionInputBackendType MotionBackend { get; set; }
|
public MotionInputBackendType MotionBackend { get; set; }
|
||||||
|
|
||||||
public Key ButtonMinus { get; set; }
|
public TKey ButtonMinus { get; set; }
|
||||||
public Key ButtonL { get; set; }
|
public TKey ButtonL { get; set; }
|
||||||
public Key ButtonZl { get; set; }
|
public TKey ButtonZl { get; set; }
|
||||||
public Key LeftButtonSl { get; set; }
|
public TKey LeftButtonSl { get; set; }
|
||||||
public Key LeftButtonSr { get; set; }
|
public TKey LeftButtonSr { get; set; }
|
||||||
public Key DpadUp { get; set; }
|
public TKey DpadUp { get; set; }
|
||||||
public Key DpadDown { get; set; }
|
public TKey DpadDown { get; set; }
|
||||||
public Key DpadLeft { get; set; }
|
public TKey DpadLeft { get; set; }
|
||||||
public Key DpadRight { get; set; }
|
public TKey DpadRight { get; set; }
|
||||||
|
|
||||||
public Key ButtonPlus { get; set; }
|
public TKey ButtonPlus { get; set; }
|
||||||
public Key ButtonR { get; set; }
|
public TKey ButtonR { get; set; }
|
||||||
public Key ButtonZr { get; set; }
|
public TKey ButtonZr { get; set; }
|
||||||
public Key RightButtonSl { get; set; }
|
public TKey RightButtonSl { get; set; }
|
||||||
public Key RightButtonSr { get; set; }
|
public TKey RightButtonSr { get; set; }
|
||||||
public Key ButtonX { get; set; }
|
public TKey ButtonX { get; set; }
|
||||||
public Key ButtonB { get; set; }
|
public TKey ButtonB { get; set; }
|
||||||
public Key ButtonY { get; set; }
|
public TKey ButtonY { get; set; }
|
||||||
public Key ButtonA { get; set; }
|
public TKey ButtonA { get; set; }
|
||||||
|
|
||||||
|
public TKey LeftStickUp { get; set; }
|
||||||
|
public TKey LeftStickDown { get; set; }
|
||||||
|
public TKey LeftStickLeft { get; set; }
|
||||||
|
public TKey LeftStickRight { get; set; }
|
||||||
|
public TKey LeftKeyboardStickButton { get; set; }
|
||||||
|
|
||||||
public Key LeftStickUp { get; set; }
|
public TKey RightStickUp { get; set; }
|
||||||
public Key LeftStickDown { get; set; }
|
public TKey RightStickDown { get; set; }
|
||||||
public Key LeftStickLeft { get; set; }
|
public TKey RightStickLeft { get; set; }
|
||||||
public Key LeftStickRight { get; set; }
|
public TKey RightStickRight { get; set; }
|
||||||
public Key LeftKeyboardStickButton { get; set; }
|
public TKey RightKeyboardStickButton { get; set; }
|
||||||
|
|
||||||
public Key RightStickUp { get; set; }
|
|
||||||
public Key RightStickDown { get; set; }
|
|
||||||
public Key RightStickLeft { get; set; }
|
|
||||||
public Key RightStickRight { get; set; }
|
|
||||||
public Key RightKeyboardStickButton { get; set; }
|
|
||||||
|
|
||||||
public int Sensitivity
|
public int Sensitivity
|
||||||
{
|
{
|
||||||
@@ -163,9 +162,9 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
public bool EnableMotion
|
public bool EnableMotion
|
||||||
{
|
{
|
||||||
get => enableMotion; set
|
get => _enableMotion; set
|
||||||
{
|
{
|
||||||
enableMotion = value;
|
_enableMotion = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -181,18 +180,18 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
public bool EnableRumble { get; set; }
|
public bool EnableRumble { get; set; }
|
||||||
public float WeakRumble
|
public float WeakRumble
|
||||||
{
|
{
|
||||||
get => weakRumble; set
|
get => _weakRumble; set
|
||||||
{
|
{
|
||||||
weakRumble = value;
|
_weakRumble = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public float StrongRumble
|
public float StrongRumble
|
||||||
{
|
{
|
||||||
get => strongRumble; set
|
get => _strongRumble; set
|
||||||
{
|
{
|
||||||
strongRumble = value;
|
_strongRumble = value;
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -209,71 +208,71 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
if (config is StandardKeyboardInputConfig keyboardConfig)
|
if (config is StandardKeyboardInputConfig keyboardConfig)
|
||||||
{
|
{
|
||||||
LeftStickUp = (Key)(object)keyboardConfig.LeftJoyconStick.StickUp;
|
LeftStickUp = (TKey)(object)keyboardConfig.LeftJoyconStick.StickUp;
|
||||||
LeftStickDown = (Key)(object)keyboardConfig.LeftJoyconStick.StickDown;
|
LeftStickDown = (TKey)(object)keyboardConfig.LeftJoyconStick.StickDown;
|
||||||
LeftStickLeft = (Key)(object)keyboardConfig.LeftJoyconStick.StickLeft;
|
LeftStickLeft = (TKey)(object)keyboardConfig.LeftJoyconStick.StickLeft;
|
||||||
LeftStickRight = (Key)(object)keyboardConfig.LeftJoyconStick.StickRight;
|
LeftStickRight = (TKey)(object)keyboardConfig.LeftJoyconStick.StickRight;
|
||||||
LeftKeyboardStickButton = (Key)(object)keyboardConfig.LeftJoyconStick.StickButton;
|
LeftKeyboardStickButton = (TKey)(object)keyboardConfig.LeftJoyconStick.StickButton;
|
||||||
|
|
||||||
RightStickUp = (Key)(object)keyboardConfig.RightJoyconStick.StickUp;
|
RightStickUp = (TKey)(object)keyboardConfig.RightJoyconStick.StickUp;
|
||||||
RightStickDown = (Key)(object)keyboardConfig.RightJoyconStick.StickDown;
|
RightStickDown = (TKey)(object)keyboardConfig.RightJoyconStick.StickDown;
|
||||||
RightStickLeft = (Key)(object)keyboardConfig.RightJoyconStick.StickLeft;
|
RightStickLeft = (TKey)(object)keyboardConfig.RightJoyconStick.StickLeft;
|
||||||
RightStickRight = (Key)(object)keyboardConfig.RightJoyconStick.StickRight;
|
RightStickRight = (TKey)(object)keyboardConfig.RightJoyconStick.StickRight;
|
||||||
RightKeyboardStickButton = (Key)(object)keyboardConfig.RightJoyconStick.StickButton;
|
RightKeyboardStickButton = (TKey)(object)keyboardConfig.RightJoyconStick.StickButton;
|
||||||
|
|
||||||
ButtonA = (Key)(object)keyboardConfig.RightJoycon.ButtonA;
|
ButtonA = (TKey)(object)keyboardConfig.RightJoycon.ButtonA;
|
||||||
ButtonB = (Key)(object)keyboardConfig.RightJoycon.ButtonB;
|
ButtonB = (TKey)(object)keyboardConfig.RightJoycon.ButtonB;
|
||||||
ButtonX = (Key)(object)keyboardConfig.RightJoycon.ButtonX;
|
ButtonX = (TKey)(object)keyboardConfig.RightJoycon.ButtonX;
|
||||||
ButtonY = (Key)(object)keyboardConfig.RightJoycon.ButtonY;
|
ButtonY = (TKey)(object)keyboardConfig.RightJoycon.ButtonY;
|
||||||
ButtonR = (Key)(object)keyboardConfig.RightJoycon.ButtonR;
|
ButtonR = (TKey)(object)keyboardConfig.RightJoycon.ButtonR;
|
||||||
RightButtonSl = (Key)(object)keyboardConfig.RightJoycon.ButtonSl;
|
RightButtonSl = (TKey)(object)keyboardConfig.RightJoycon.ButtonSl;
|
||||||
RightButtonSr = (Key)(object)keyboardConfig.RightJoycon.ButtonSr;
|
RightButtonSr = (TKey)(object)keyboardConfig.RightJoycon.ButtonSr;
|
||||||
ButtonZr = (Key)(object)keyboardConfig.RightJoycon.ButtonZr;
|
ButtonZr = (TKey)(object)keyboardConfig.RightJoycon.ButtonZr;
|
||||||
ButtonPlus = (Key)(object)keyboardConfig.RightJoycon.ButtonPlus;
|
ButtonPlus = (TKey)(object)keyboardConfig.RightJoycon.ButtonPlus;
|
||||||
|
|
||||||
DpadUp = (Key)(object)keyboardConfig.LeftJoycon.DpadUp;
|
DpadUp = (TKey)(object)keyboardConfig.LeftJoycon.DpadUp;
|
||||||
DpadDown = (Key)(object)keyboardConfig.LeftJoycon.DpadDown;
|
DpadDown = (TKey)(object)keyboardConfig.LeftJoycon.DpadDown;
|
||||||
DpadLeft = (Key)(object)keyboardConfig.LeftJoycon.DpadLeft;
|
DpadLeft = (TKey)(object)keyboardConfig.LeftJoycon.DpadLeft;
|
||||||
DpadRight = (Key)(object)keyboardConfig.LeftJoycon.DpadRight;
|
DpadRight = (TKey)(object)keyboardConfig.LeftJoycon.DpadRight;
|
||||||
ButtonMinus = (Key)(object)keyboardConfig.LeftJoycon.ButtonMinus;
|
ButtonMinus = (TKey)(object)keyboardConfig.LeftJoycon.ButtonMinus;
|
||||||
LeftButtonSl = (Key)(object)keyboardConfig.LeftJoycon.ButtonSl;
|
LeftButtonSl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSl;
|
||||||
LeftButtonSr = (Key)(object)keyboardConfig.LeftJoycon.ButtonSr;
|
LeftButtonSr = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSr;
|
||||||
ButtonZl = (Key)(object)keyboardConfig.LeftJoycon.ButtonZl;
|
ButtonZl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonZl;
|
||||||
ButtonL = (Key)(object)keyboardConfig.LeftJoycon.ButtonL;
|
ButtonL = (TKey)(object)keyboardConfig.LeftJoycon.ButtonL;
|
||||||
}
|
}
|
||||||
else if (config is StandardControllerInputConfig controllerConfig)
|
else if (config is StandardControllerInputConfig controllerConfig)
|
||||||
{
|
{
|
||||||
LeftJoystick = (Stick)(object)controllerConfig.LeftJoyconStick.Joystick;
|
LeftJoystick = (TStick)(object)controllerConfig.LeftJoyconStick.Joystick;
|
||||||
LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX;
|
LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX;
|
||||||
LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY;
|
LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY;
|
||||||
LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW;
|
LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW;
|
||||||
LeftControllerStickButton = (Key)(object)controllerConfig.LeftJoyconStick.StickButton;
|
LeftControllerStickButton = (TKey)(object)controllerConfig.LeftJoyconStick.StickButton;
|
||||||
|
|
||||||
RightJoystick = (Stick)(object)controllerConfig.RightJoyconStick.Joystick;
|
RightJoystick = (TStick)(object)controllerConfig.RightJoyconStick.Joystick;
|
||||||
RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX;
|
RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX;
|
||||||
RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY;
|
RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY;
|
||||||
RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW;
|
RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW;
|
||||||
RightControllerStickButton = (Key)(object)controllerConfig.RightJoyconStick.StickButton;
|
RightControllerStickButton = (TKey)(object)controllerConfig.RightJoyconStick.StickButton;
|
||||||
|
|
||||||
ButtonA = (Key)(object)controllerConfig.RightJoycon.ButtonA;
|
ButtonA = (TKey)(object)controllerConfig.RightJoycon.ButtonA;
|
||||||
ButtonB = (Key)(object)controllerConfig.RightJoycon.ButtonB;
|
ButtonB = (TKey)(object)controllerConfig.RightJoycon.ButtonB;
|
||||||
ButtonX = (Key)(object)controllerConfig.RightJoycon.ButtonX;
|
ButtonX = (TKey)(object)controllerConfig.RightJoycon.ButtonX;
|
||||||
ButtonY = (Key)(object)controllerConfig.RightJoycon.ButtonY;
|
ButtonY = (TKey)(object)controllerConfig.RightJoycon.ButtonY;
|
||||||
ButtonR = (Key)(object)controllerConfig.RightJoycon.ButtonR;
|
ButtonR = (TKey)(object)controllerConfig.RightJoycon.ButtonR;
|
||||||
RightButtonSl = (Key)(object)controllerConfig.RightJoycon.ButtonSl;
|
RightButtonSl = (TKey)(object)controllerConfig.RightJoycon.ButtonSl;
|
||||||
RightButtonSr = (Key)(object)controllerConfig.RightJoycon.ButtonSr;
|
RightButtonSr = (TKey)(object)controllerConfig.RightJoycon.ButtonSr;
|
||||||
ButtonZr = (Key)(object)controllerConfig.RightJoycon.ButtonZr;
|
ButtonZr = (TKey)(object)controllerConfig.RightJoycon.ButtonZr;
|
||||||
ButtonPlus = (Key)(object)controllerConfig.RightJoycon.ButtonPlus;
|
ButtonPlus = (TKey)(object)controllerConfig.RightJoycon.ButtonPlus;
|
||||||
|
|
||||||
DpadUp = (Key)(object)controllerConfig.LeftJoycon.DpadUp;
|
DpadUp = (TKey)(object)controllerConfig.LeftJoycon.DpadUp;
|
||||||
DpadDown = (Key)(object)controllerConfig.LeftJoycon.DpadDown;
|
DpadDown = (TKey)(object)controllerConfig.LeftJoycon.DpadDown;
|
||||||
DpadLeft = (Key)(object)controllerConfig.LeftJoycon.DpadLeft;
|
DpadLeft = (TKey)(object)controllerConfig.LeftJoycon.DpadLeft;
|
||||||
DpadRight = (Key)(object)controllerConfig.LeftJoycon.DpadRight;
|
DpadRight = (TKey)(object)controllerConfig.LeftJoycon.DpadRight;
|
||||||
ButtonMinus = (Key)(object)controllerConfig.LeftJoycon.ButtonMinus;
|
ButtonMinus = (TKey)(object)controllerConfig.LeftJoycon.ButtonMinus;
|
||||||
LeftButtonSl = (Key)(object)controllerConfig.LeftJoycon.ButtonSl;
|
LeftButtonSl = (TKey)(object)controllerConfig.LeftJoycon.ButtonSl;
|
||||||
LeftButtonSr = (Key)(object)controllerConfig.LeftJoycon.ButtonSr;
|
LeftButtonSr = (TKey)(object)controllerConfig.LeftJoycon.ButtonSr;
|
||||||
ButtonZl = (Key)(object)controllerConfig.LeftJoycon.ButtonZl;
|
ButtonZl = (TKey)(object)controllerConfig.LeftJoycon.ButtonZl;
|
||||||
ButtonL = (Key)(object)controllerConfig.LeftJoycon.ButtonL;
|
ButtonL = (TKey)(object)controllerConfig.LeftJoycon.ButtonL;
|
||||||
|
|
||||||
DeadzoneLeft = controllerConfig.DeadzoneLeft;
|
DeadzoneLeft = controllerConfig.DeadzoneLeft;
|
||||||
DeadzoneRight = controllerConfig.DeadzoneRight;
|
DeadzoneRight = controllerConfig.DeadzoneRight;
|
||||||
@@ -317,65 +316,66 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
{
|
{
|
||||||
if (Backend == InputBackendType.WindowKeyboard)
|
if (Backend == InputBackendType.WindowKeyboard)
|
||||||
{
|
{
|
||||||
return new StandardKeyboardInputConfig()
|
return new StandardKeyboardInputConfig
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
Backend = Backend,
|
Backend = Backend,
|
||||||
PlayerIndex = PlayerIndex,
|
PlayerIndex = PlayerIndex,
|
||||||
ControllerType = ControllerType,
|
ControllerType = ControllerType,
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<Ryujinx.Common.Configuration.Hid.Key>()
|
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
||||||
{
|
{
|
||||||
DpadUp = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadUp,
|
DpadUp = (Key)(object)DpadUp,
|
||||||
DpadDown = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadDown,
|
DpadDown = (Key)(object)DpadDown,
|
||||||
DpadLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadLeft,
|
DpadLeft = (Key)(object)DpadLeft,
|
||||||
DpadRight = (Ryujinx.Common.Configuration.Hid.Key)(object)DpadRight,
|
DpadRight = (Key)(object)DpadRight,
|
||||||
ButtonL = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonL,
|
ButtonL = (Key)(object)ButtonL,
|
||||||
ButtonZl = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonZl,
|
ButtonZl = (Key)(object)ButtonZl,
|
||||||
ButtonSl = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftButtonSl,
|
ButtonSl = (Key)(object)LeftButtonSl,
|
||||||
ButtonSr = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftButtonSr,
|
ButtonSr = (Key)(object)LeftButtonSr,
|
||||||
ButtonMinus = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonMinus
|
ButtonMinus = (Key)(object)ButtonMinus,
|
||||||
},
|
},
|
||||||
RightJoycon = new RightJoyconCommonConfig<Ryujinx.Common.Configuration.Hid.Key>()
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||||
{
|
{
|
||||||
ButtonA = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonA,
|
ButtonA = (Key)(object)ButtonA,
|
||||||
ButtonB = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonB,
|
ButtonB = (Key)(object)ButtonB,
|
||||||
ButtonX = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonX,
|
ButtonX = (Key)(object)ButtonX,
|
||||||
ButtonY = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonY,
|
ButtonY = (Key)(object)ButtonY,
|
||||||
ButtonPlus = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonPlus,
|
ButtonPlus = (Key)(object)ButtonPlus,
|
||||||
ButtonSl = (Ryujinx.Common.Configuration.Hid.Key)(object)RightButtonSl,
|
ButtonSl = (Key)(object)RightButtonSl,
|
||||||
ButtonSr = (Ryujinx.Common.Configuration.Hid.Key)(object)RightButtonSr,
|
ButtonSr = (Key)(object)RightButtonSr,
|
||||||
ButtonR = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonR,
|
ButtonR = (Key)(object)ButtonR,
|
||||||
ButtonZr = (Ryujinx.Common.Configuration.Hid.Key)(object)ButtonZr
|
ButtonZr = (Key)(object)ButtonZr,
|
||||||
},
|
},
|
||||||
LeftJoyconStick = new JoyconConfigKeyboardStick<Ryujinx.Common.Configuration.Hid.Key>()
|
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
{
|
{
|
||||||
StickUp = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickUp,
|
StickUp = (Key)(object)LeftStickUp,
|
||||||
StickDown = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickDown,
|
StickDown = (Key)(object)LeftStickDown,
|
||||||
StickRight = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickRight,
|
StickRight = (Key)(object)LeftStickRight,
|
||||||
StickLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftStickLeft,
|
StickLeft = (Key)(object)LeftStickLeft,
|
||||||
StickButton = (Ryujinx.Common.Configuration.Hid.Key)(object)LeftKeyboardStickButton
|
StickButton = (Key)(object)LeftKeyboardStickButton,
|
||||||
},
|
},
|
||||||
RightJoyconStick = new JoyconConfigKeyboardStick<Ryujinx.Common.Configuration.Hid.Key>()
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
{
|
{
|
||||||
StickUp = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickUp,
|
StickUp = (Key)(object)RightStickUp,
|
||||||
StickDown = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickDown,
|
StickDown = (Key)(object)RightStickDown,
|
||||||
StickLeft = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickLeft,
|
StickLeft = (Key)(object)RightStickLeft,
|
||||||
StickRight = (Ryujinx.Common.Configuration.Hid.Key)(object)RightStickRight,
|
StickRight = (Key)(object)RightStickRight,
|
||||||
StickButton = (Ryujinx.Common.Configuration.Hid.Key)(object)RightKeyboardStickButton
|
StickButton = (Key)(object)RightKeyboardStickButton,
|
||||||
},
|
},
|
||||||
Version = InputConfig.CurrentVersion
|
Version = InputConfig.CurrentVersion,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Backend == InputBackendType.GamepadSDL2)
|
|
||||||
|
if (Backend == InputBackendType.GamepadSDL2)
|
||||||
{
|
{
|
||||||
var config = new StandardControllerInputConfig()
|
var config = new StandardControllerInputConfig
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
Backend = Backend,
|
Backend = Backend,
|
||||||
PlayerIndex = PlayerIndex,
|
PlayerIndex = PlayerIndex,
|
||||||
ControllerType = ControllerType,
|
ControllerType = ControllerType,
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>()
|
LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>
|
||||||
{
|
{
|
||||||
DpadUp = (GamepadInputId)(object)DpadUp,
|
DpadUp = (GamepadInputId)(object)DpadUp,
|
||||||
DpadDown = (GamepadInputId)(object)DpadDown,
|
DpadDown = (GamepadInputId)(object)DpadDown,
|
||||||
@@ -387,7 +387,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
ButtonSr = (GamepadInputId)(object)LeftButtonSr,
|
ButtonSr = (GamepadInputId)(object)LeftButtonSr,
|
||||||
ButtonMinus = (GamepadInputId)(object)ButtonMinus,
|
ButtonMinus = (GamepadInputId)(object)ButtonMinus,
|
||||||
},
|
},
|
||||||
RightJoycon = new RightJoyconCommonConfig<GamepadInputId>()
|
RightJoycon = new RightJoyconCommonConfig<GamepadInputId>
|
||||||
{
|
{
|
||||||
ButtonA = (GamepadInputId)(object)ButtonA,
|
ButtonA = (GamepadInputId)(object)ButtonA,
|
||||||
ButtonB = (GamepadInputId)(object)ButtonB,
|
ButtonB = (GamepadInputId)(object)ButtonB,
|
||||||
@@ -399,7 +399,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
ButtonR = (GamepadInputId)(object)ButtonR,
|
ButtonR = (GamepadInputId)(object)ButtonR,
|
||||||
ButtonZr = (GamepadInputId)(object)ButtonZr,
|
ButtonZr = (GamepadInputId)(object)ButtonZr,
|
||||||
},
|
},
|
||||||
LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>()
|
LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
|
||||||
{
|
{
|
||||||
Joystick = (StickInputId)(object)LeftJoystick,
|
Joystick = (StickInputId)(object)LeftJoystick,
|
||||||
InvertStickX = LeftInvertStickX,
|
InvertStickX = LeftInvertStickX,
|
||||||
@@ -407,7 +407,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
Rotate90CW = LeftRotate90,
|
Rotate90CW = LeftRotate90,
|
||||||
StickButton = (GamepadInputId)(object)LeftControllerStickButton,
|
StickButton = (GamepadInputId)(object)LeftControllerStickButton,
|
||||||
},
|
},
|
||||||
RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>()
|
RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId>
|
||||||
{
|
{
|
||||||
Joystick = (StickInputId)(object)RightJoystick,
|
Joystick = (StickInputId)(object)RightJoystick,
|
||||||
InvertStickX = RightInvertStickX,
|
InvertStickX = RightInvertStickX,
|
||||||
@@ -415,11 +415,11 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
Rotate90CW = RightRotate90,
|
Rotate90CW = RightRotate90,
|
||||||
StickButton = (GamepadInputId)(object)RightControllerStickButton,
|
StickButton = (GamepadInputId)(object)RightControllerStickButton,
|
||||||
},
|
},
|
||||||
Rumble = new RumbleConfigController()
|
Rumble = new RumbleConfigController
|
||||||
{
|
{
|
||||||
EnableRumble = EnableRumble,
|
EnableRumble = EnableRumble,
|
||||||
WeakRumble = WeakRumble,
|
WeakRumble = WeakRumble,
|
||||||
StrongRumble = StrongRumble
|
StrongRumble = StrongRumble,
|
||||||
},
|
},
|
||||||
Version = InputConfig.CurrentVersion,
|
Version = InputConfig.CurrentVersion,
|
||||||
DeadzoneLeft = DeadzoneLeft,
|
DeadzoneLeft = DeadzoneLeft,
|
||||||
@@ -428,19 +428,19 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
RangeRight = RangeRight,
|
RangeRight = RangeRight,
|
||||||
TriggerThreshold = TriggerThreshold,
|
TriggerThreshold = TriggerThreshold,
|
||||||
Motion = EnableCemuHookMotion
|
Motion = EnableCemuHookMotion
|
||||||
? new CemuHookMotionConfigController()
|
? new CemuHookMotionConfigController
|
||||||
{
|
{
|
||||||
DsuServerHost = DsuServerHost,
|
DsuServerHost = DsuServerHost,
|
||||||
DsuServerPort = DsuServerPort,
|
DsuServerPort = DsuServerPort,
|
||||||
Slot = Slot,
|
Slot = Slot,
|
||||||
AltSlot = AltSlot,
|
AltSlot = AltSlot,
|
||||||
MirrorInput = MirrorInput,
|
MirrorInput = MirrorInput,
|
||||||
MotionBackend = MotionInputBackendType.CemuHook
|
MotionBackend = MotionInputBackendType.CemuHook,
|
||||||
}
|
}
|
||||||
: new StandardMotionConfigController()
|
: new StandardMotionConfigController
|
||||||
{
|
{
|
||||||
MotionBackend = MotionInputBackendType.GamepadDriver
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
config.Motion.Sensitivity = Sensitivity;
|
config.Motion.Sensitivity = Sensitivity;
|
||||||
|
@@ -8,6 +8,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Models
|
namespace Ryujinx.Ava.UI.Models
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
return "0 KiB";
|
return "0 KiB";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveModel(SaveDataInfo info, VirtualFileSystem virtualFileSystem)
|
public SaveModel(SaveDataInfo info)
|
||||||
{
|
{
|
||||||
SaveId = info.SaveDataId;
|
SaveId = info.SaveDataId;
|
||||||
TitleId = info.ProgramId;
|
TitleId = info.ProgramId;
|
||||||
@@ -81,10 +82,11 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var saveRoot = System.IO.Path.Combine(virtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
|
var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
|
||||||
|
|
||||||
long total_size = GetDirectorySize(saveRoot);
|
long totalSize = GetDirectorySize(saveRoot);
|
||||||
long GetDirectorySize(string path)
|
|
||||||
|
static long GetDirectorySize(string path)
|
||||||
{
|
{
|
||||||
long size = 0;
|
long size = 0;
|
||||||
if (Directory.Exists(path))
|
if (Directory.Exists(path))
|
||||||
@@ -105,7 +107,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size = total_size;
|
Size = totalSize;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
private string _name = String.Empty;
|
private string _name = String.Empty;
|
||||||
private UserId _userId;
|
private UserId _userId;
|
||||||
|
|
||||||
public uint MaxProfileNameLength => 0x20;
|
public static uint MaxProfileNameLength => 0x20;
|
||||||
|
|
||||||
public byte[] Image
|
public byte[] Image
|
||||||
{
|
{
|
||||||
|
@@ -87,7 +87,8 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
|
|
||||||
private void UpdateBackground()
|
private void UpdateBackground()
|
||||||
{
|
{
|
||||||
Avalonia.Application.Current.Styles.TryGetResource("ControlFillColorSecondary", out object color);
|
var currentApplication = Avalonia.Application.Current;
|
||||||
|
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
|
||||||
|
|
||||||
if (color is not null)
|
if (color is not null)
|
||||||
{
|
{
|
||||||
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||||
|
|
||||||
public event EventHandler<IntPtr> WindowCreated;
|
public event EventHandler<IntPtr> WindowCreated;
|
||||||
public event EventHandler<Size> SizeChanged;
|
public event EventHandler<Size> BoundsChanged;
|
||||||
|
|
||||||
public EmbeddedWindow()
|
public EmbeddedWindow()
|
||||||
{
|
{
|
||||||
@@ -67,7 +67,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
|
|
||||||
private void StateChanged(Rect rect)
|
private void StateChanged(Rect rect)
|
||||||
{
|
{
|
||||||
SizeChanged?.Invoke(this, rect.Size);
|
BoundsChanged?.Invoke(this, rect.Size);
|
||||||
_updateBoundsCallback?.Invoke(rect);
|
_updateBoundsCallback?.Invoke(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +77,13 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
{
|
{
|
||||||
return CreateLinux(control);
|
return CreateLinux(control);
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsWindows())
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
return CreateWin32(control);
|
return CreateWin32(control);
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsMacOS())
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
return CreateMacOS();
|
return CreateMacOS();
|
||||||
}
|
}
|
||||||
@@ -141,28 +143,29 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
{
|
{
|
||||||
if (VisualRoot != null)
|
if (VisualRoot != null)
|
||||||
{
|
{
|
||||||
if (msg == WindowsMessages.LBUTTONDOWN ||
|
if (msg == WindowsMessages.Lbuttondown ||
|
||||||
msg == WindowsMessages.RBUTTONDOWN ||
|
msg == WindowsMessages.Rbuttondown ||
|
||||||
msg == WindowsMessages.LBUTTONUP ||
|
msg == WindowsMessages.Lbuttonup ||
|
||||||
msg == WindowsMessages.RBUTTONUP ||
|
msg == WindowsMessages.Rbuttonup ||
|
||||||
msg == WindowsMessages.MOUSEMOVE)
|
msg == WindowsMessages.Mousemove)
|
||||||
{
|
{
|
||||||
Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), VisualRoot).Value;
|
Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), this).Value;
|
||||||
Pointer pointer = new(0, PointerType.Mouse, true);
|
Pointer pointer = new(0, PointerType.Mouse, true);
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete (As of Avalonia 11, the constructors for PointerPressedEventArgs & PointerEventArgs are marked as obsolete)
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WindowsMessages.LBUTTONDOWN:
|
case WindowsMessages.Lbuttondown:
|
||||||
case WindowsMessages.RBUTTONDOWN:
|
case WindowsMessages.Rbuttondown:
|
||||||
{
|
{
|
||||||
bool isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
bool isLeft = msg == WindowsMessages.Lbuttondown;
|
||||||
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
||||||
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed);
|
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed);
|
||||||
|
|
||||||
var evnt = new PointerPressedEventArgs(
|
var evnt = new PointerPressedEventArgs(
|
||||||
this,
|
this,
|
||||||
pointer,
|
pointer,
|
||||||
VisualRoot,
|
this,
|
||||||
rootVisualPosition,
|
rootVisualPosition,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
properties,
|
properties,
|
||||||
@@ -172,17 +175,17 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WindowsMessages.LBUTTONUP:
|
case WindowsMessages.Lbuttonup:
|
||||||
case WindowsMessages.RBUTTONUP:
|
case WindowsMessages.Rbuttonup:
|
||||||
{
|
{
|
||||||
bool isLeft = msg == WindowsMessages.LBUTTONUP;
|
bool isLeft = msg == WindowsMessages.Lbuttonup;
|
||||||
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton;
|
||||||
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased);
|
PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased);
|
||||||
|
|
||||||
var evnt = new PointerReleasedEventArgs(
|
var evnt = new PointerReleasedEventArgs(
|
||||||
this,
|
this,
|
||||||
pointer,
|
pointer,
|
||||||
VisualRoot,
|
this,
|
||||||
rootVisualPosition,
|
rootVisualPosition,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
properties,
|
properties,
|
||||||
@@ -193,13 +196,13 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WindowsMessages.MOUSEMOVE:
|
case WindowsMessages.Mousemove:
|
||||||
{
|
{
|
||||||
var evnt = new PointerEventArgs(
|
var evnt = new PointerEventArgs(
|
||||||
PointerMovedEvent,
|
PointerMovedEvent,
|
||||||
this,
|
this,
|
||||||
pointer,
|
pointer,
|
||||||
VisualRoot,
|
this,
|
||||||
rootVisualPosition,
|
rootVisualPosition,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
||||||
@@ -210,25 +213,26 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||||
};
|
};
|
||||||
|
|
||||||
WNDCLASSEX wndClassEx = new()
|
WndClassEx wndClassEx = new()
|
||||||
{
|
{
|
||||||
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
|
cbSize = Marshal.SizeOf<WndClassEx>(),
|
||||||
hInstance = GetModuleHandle(null),
|
hInstance = GetModuleHandle(null),
|
||||||
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
|
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
|
||||||
style = ClassStyles.CS_OWNDC,
|
style = ClassStyles.CsOwndc,
|
||||||
lpszClassName = Marshal.StringToHGlobalUni(_className),
|
lpszClassName = Marshal.StringToHGlobalUni(_className),
|
||||||
hCursor = CreateArrowCursor()
|
hCursor = CreateArrowCursor(),
|
||||||
};
|
};
|
||||||
|
|
||||||
RegisterClassEx(ref wndClassEx);
|
RegisterClassEx(ref wndClassEx);
|
||||||
|
|
||||||
WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WS_CHILD, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WsChild, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||||
|
|
||||||
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
|
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
|
||||||
|
|
||||||
@@ -280,9 +284,11 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
|
#pragma warning disable CA1822 // Mark member as static
|
||||||
void DestroyMacOS()
|
void DestroyMacOS()
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1822
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase));
|
return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SurfaceKHR CreateSurface(Instance instance, Vk api)
|
public SurfaceKHR CreateSurface(Instance instance, Vk _)
|
||||||
{
|
{
|
||||||
return CreateSurface(instance);
|
return CreateSurface(instance);
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
public readonly EmbeddedWindow EmbeddedWindow;
|
public readonly EmbeddedWindow EmbeddedWindow;
|
||||||
|
|
||||||
public event EventHandler<EventArgs> WindowCreated;
|
public event EventHandler<EventArgs> WindowCreated;
|
||||||
public event Action<object, Size> SizeChanged;
|
public event Action<object, Size> BoundsChanged;
|
||||||
|
|
||||||
public RendererHost()
|
public RendererHost()
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
private void Initialize()
|
private void Initialize()
|
||||||
{
|
{
|
||||||
EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated;
|
EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||||
EmbeddedWindow.SizeChanged += CurrentWindow_SizeChanged;
|
EmbeddedWindow.BoundsChanged += CurrentWindow_BoundsChanged;
|
||||||
|
|
||||||
Content = EmbeddedWindow;
|
Content = EmbeddedWindow;
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
if (EmbeddedWindow != null)
|
if (EmbeddedWindow != null)
|
||||||
{
|
{
|
||||||
EmbeddedWindow.WindowCreated -= CurrentWindow_WindowCreated;
|
EmbeddedWindow.WindowCreated -= CurrentWindow_WindowCreated;
|
||||||
EmbeddedWindow.SizeChanged -= CurrentWindow_SizeChanged;
|
EmbeddedWindow.BoundsChanged -= CurrentWindow_BoundsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
@@ -55,9 +55,9 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CurrentWindow_SizeChanged(object sender, Size e)
|
private void CurrentWindow_BoundsChanged(object sender, Size e)
|
||||||
{
|
{
|
||||||
SizeChanged?.Invoke(sender, e);
|
BoundsChanged?.Invoke(sender, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CurrentWindow_WindowCreated(object sender, IntPtr e)
|
private void CurrentWindow_WindowCreated(object sender, IntPtr e)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Platform;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
@@ -87,21 +87,19 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
Version = Program.Version;
|
Version = Program.Version;
|
||||||
|
|
||||||
var assets = AvaloniaLocator.Current.GetService<Avalonia.Platform.IAssetLoader>();
|
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light")
|
if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light")
|
||||||
{
|
{
|
||||||
GithubLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.Ui.Common")));
|
GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
DiscordLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.Ui.Common")));
|
DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
PatreonLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.Ui.Common")));
|
PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
TwitterLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.Ui.Common")));
|
TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.Ui.Common")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GithubLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.Ui.Common")));
|
GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
DiscordLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.Ui.Common")));
|
DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
PatreonLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.Ui.Common")));
|
PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
TwitterLogo = new Bitmap(assets.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.Ui.Common")));
|
TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.Ui.Common")));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson);
|
Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson);
|
||||||
|
@@ -18,7 +18,6 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
@@ -44,7 +43,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private bool _useRandomUuid;
|
private bool _useRandomUuid;
|
||||||
private string _usage;
|
private string _usage;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
||||||
{
|
{
|
||||||
@@ -52,7 +51,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
_httpClient = new HttpClient
|
_httpClient = new HttpClient
|
||||||
{
|
{
|
||||||
Timeout = TimeSpan.FromSeconds(30)
|
Timeout = TimeSpan.FromSeconds(30),
|
||||||
};
|
};
|
||||||
|
|
||||||
LastScannedAmiiboId = lastScannedAmiiboId;
|
LastScannedAmiiboId = lastScannedAmiiboId;
|
||||||
@@ -185,6 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
_httpClient.Dispose();
|
_httpClient.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
|
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
|
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
ParseAmiiboData();
|
ParseAmiiboData();
|
||||||
@@ -426,8 +426,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
|
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
|
||||||
using (MemoryStream memoryStream = new(amiiboPreviewBytes))
|
using MemoryStream memoryStream = new(amiiboPreviewBytes);
|
||||||
{
|
|
||||||
Bitmap bitmap = new(memoryStream);
|
Bitmap bitmap = new(memoryStream);
|
||||||
|
|
||||||
double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width,
|
double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width,
|
||||||
@@ -438,7 +438,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
|
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}");
|
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}");
|
||||||
@@ -447,15 +446,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private void ResetAmiiboPreview()
|
private void ResetAmiiboPreview()
|
||||||
{
|
{
|
||||||
using (MemoryStream memoryStream = new(_amiiboLogoBytes))
|
using MemoryStream memoryStream = new(_amiiboLogoBytes);
|
||||||
{
|
|
||||||
Bitmap bitmap = new(memoryStream);
|
Bitmap bitmap = new(memoryStream);
|
||||||
|
|
||||||
AmiiboImage = bitmap;
|
AmiiboImage = bitmap;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async void ShowInfoDialog()
|
private static async void ShowInfoDialog()
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],
|
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],
|
||||||
|
@@ -1,363 +0,0 @@
|
|||||||
using Avalonia.Media;
|
|
||||||
using DynamicData;
|
|
||||||
using LibHac.Common;
|
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.Fs.Fsa;
|
|
||||||
using LibHac.FsSystem;
|
|
||||||
using LibHac.Ncm;
|
|
||||||
using LibHac.Tools.Fs;
|
|
||||||
using LibHac.Tools.FsSystem;
|
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
|
||||||
using Ryujinx.Ava.UI.Models;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.Formats.Png;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using System;
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Color = Avalonia.Media.Color;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
|
||||||
{
|
|
||||||
internal class AvatarProfileViewModel : BaseModel, IDisposable
|
|
||||||
{
|
|
||||||
private const int MaxImageTasks = 4;
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, byte[]> _avatarStore = new();
|
|
||||||
private static bool _isPreloading;
|
|
||||||
private static Action _loadCompleteAction;
|
|
||||||
|
|
||||||
private ObservableCollection<ProfileImageModel> _images;
|
|
||||||
private Color _backgroundColor = Colors.White;
|
|
||||||
|
|
||||||
private int _selectedIndex;
|
|
||||||
private int _imagesLoaded;
|
|
||||||
private bool _isActive;
|
|
||||||
private byte[] _selectedImage;
|
|
||||||
private bool _isIndeterminate = true;
|
|
||||||
|
|
||||||
public bool IsActive
|
|
||||||
{
|
|
||||||
get => _isActive;
|
|
||||||
set => _isActive = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarProfileViewModel()
|
|
||||||
{
|
|
||||||
_images = new ObservableCollection<ProfileImageModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarProfileViewModel(Action loadCompleteAction)
|
|
||||||
{
|
|
||||||
_images = new ObservableCollection<ProfileImageModel>();
|
|
||||||
|
|
||||||
if (_isPreloading)
|
|
||||||
{
|
|
||||||
_loadCompleteAction = loadCompleteAction;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReloadImages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color BackgroundColor
|
|
||||||
{
|
|
||||||
get => _backgroundColor;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_backgroundColor = value;
|
|
||||||
|
|
||||||
IsActive = false;
|
|
||||||
|
|
||||||
ReloadImages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<ProfileImageModel> Images
|
|
||||||
{
|
|
||||||
get => _images;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_images = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsIndeterminate
|
|
||||||
{
|
|
||||||
get => _isIndeterminate;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_isIndeterminate = value;
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ImageCount => _avatarStore.Count;
|
|
||||||
|
|
||||||
public int ImagesLoaded
|
|
||||||
{
|
|
||||||
get => _imagesLoaded;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_imagesLoaded = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SelectedIndex
|
|
||||||
{
|
|
||||||
get => _selectedIndex;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_selectedIndex = value;
|
|
||||||
|
|
||||||
if (_selectedIndex == -1)
|
|
||||||
{
|
|
||||||
SelectedImage = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedImage = _images[_selectedIndex].Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] SelectedImage
|
|
||||||
{
|
|
||||||
get => _selectedImage;
|
|
||||||
private set => _selectedImage = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadImages()
|
|
||||||
{
|
|
||||||
if (_isPreloading)
|
|
||||||
{
|
|
||||||
IsIndeterminate = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
IsActive = true;
|
|
||||||
|
|
||||||
Images.Clear();
|
|
||||||
int selectedIndex = _selectedIndex;
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
ImagesLoaded = 0;
|
|
||||||
IsIndeterminate = false;
|
|
||||||
|
|
||||||
var keys = _avatarStore.Keys.ToList();
|
|
||||||
|
|
||||||
var newImages = new List<ProfileImageModel>();
|
|
||||||
var tasks = new List<Task>();
|
|
||||||
|
|
||||||
for (int i = 0; i < MaxImageTasks; i++)
|
|
||||||
{
|
|
||||||
var start = i;
|
|
||||||
tasks.Add(Task.Run(() => ImageTask(start)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.WaitAll(tasks.ToArray());
|
|
||||||
|
|
||||||
Images.AddRange(newImages);
|
|
||||||
|
|
||||||
void ImageTask(int start)
|
|
||||||
{
|
|
||||||
for (int i = start; i < keys.Count; i += MaxImageTasks)
|
|
||||||
{
|
|
||||||
if (!IsActive)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = keys[i];
|
|
||||||
var image = _avatarStore[keys[i]];
|
|
||||||
|
|
||||||
var data = ProcessImage(image);
|
|
||||||
newImages.Add(new ProfileImageModel(key, data));
|
|
||||||
if (index++ == selectedIndex)
|
|
||||||
{
|
|
||||||
SelectedImage = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Interlocked.Increment(ref _imagesLoaded);
|
|
||||||
OnPropertyChanged(nameof(ImagesLoaded));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] ProcessImage(byte[] data)
|
|
||||||
{
|
|
||||||
using (MemoryStream streamJpg = new())
|
|
||||||
{
|
|
||||||
Image avatarImage = Image.Load(data, new PngDecoder());
|
|
||||||
|
|
||||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(BackgroundColor.R,
|
|
||||||
BackgroundColor.G,
|
|
||||||
BackgroundColor.B,
|
|
||||||
BackgroundColor.A)));
|
|
||||||
avatarImage.SaveAsJpeg(streamJpg);
|
|
||||||
|
|
||||||
return streamJpg.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_avatarStore.Count > 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_isPreloading = true;
|
|
||||||
|
|
||||||
string contentPath =
|
|
||||||
contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem,
|
|
||||||
NcaContentType.Data);
|
|
||||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
|
||||||
{
|
|
||||||
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
|
|
||||||
{
|
|
||||||
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
|
||||||
|
|
||||||
foreach (DirectoryEntryEx item in romfs.EnumerateEntries())
|
|
||||||
{
|
|
||||||
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
|
|
||||||
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") &&
|
|
||||||
item.FullPath.Contains("szs"))
|
|
||||||
{
|
|
||||||
using var file = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read)
|
|
||||||
.ThrowIfFailure();
|
|
||||||
|
|
||||||
using (MemoryStream stream = new())
|
|
||||||
using (MemoryStream streamPng = new())
|
|
||||||
{
|
|
||||||
file.Get.AsStream().CopyTo(stream);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
|
||||||
|
|
||||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
|
||||||
|
|
||||||
avatarImage.SaveAsPng(streamPng);
|
|
||||||
|
|
||||||
_avatarStore.Add(item.FullPath, streamPng.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_isPreloading = false;
|
|
||||||
_loadCompleteAction?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] DecompressYaz0(Stream stream)
|
|
||||||
{
|
|
||||||
using (BinaryReader reader = new(stream))
|
|
||||||
{
|
|
||||||
reader.ReadInt32(); // Magic
|
|
||||||
|
|
||||||
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
|
||||||
|
|
||||||
reader.ReadInt64(); // Padding
|
|
||||||
|
|
||||||
byte[] input = new byte[stream.Length - stream.Position];
|
|
||||||
stream.Read(input, 0, input.Length);
|
|
||||||
|
|
||||||
uint inputOffset = 0;
|
|
||||||
|
|
||||||
byte[] output = new byte[decodedLength];
|
|
||||||
uint outputOffset = 0;
|
|
||||||
|
|
||||||
ushort mask = 0;
|
|
||||||
byte header = 0;
|
|
||||||
|
|
||||||
while (outputOffset < decodedLength)
|
|
||||||
{
|
|
||||||
if ((mask >>= 1) == 0)
|
|
||||||
{
|
|
||||||
header = input[inputOffset++];
|
|
||||||
mask = 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((header & mask) != 0)
|
|
||||||
{
|
|
||||||
if (outputOffset == output.Length)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
output[outputOffset++] = input[inputOffset++];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte byte1 = input[inputOffset++];
|
|
||||||
byte byte2 = input[inputOffset++];
|
|
||||||
|
|
||||||
uint dist = (uint)((byte1 & 0xF) << 8) | byte2;
|
|
||||||
uint position = outputOffset - (dist + 1);
|
|
||||||
|
|
||||||
uint length = (uint)byte1 >> 4;
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
length = (uint)input[inputOffset++] + 0x12;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
length += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint gap = outputOffset - position;
|
|
||||||
uint nonOverlappingLength = length;
|
|
||||||
|
|
||||||
if (nonOverlappingLength > gap)
|
|
||||||
{
|
|
||||||
nonOverlappingLength = gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength);
|
|
||||||
outputOffset += nonOverlappingLength;
|
|
||||||
position += nonOverlappingLength;
|
|
||||||
length -= nonOverlappingLength;
|
|
||||||
|
|
||||||
while (length-- > 0)
|
|
||||||
{
|
|
||||||
output[outputOffset++] = output[position++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_loadCompleteAction = null;
|
|
||||||
IsActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
@@ -44,15 +45,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private PlayerIndex _playerId;
|
private PlayerIndex _playerId;
|
||||||
private int _controller;
|
private int _controller;
|
||||||
private int _controllerNumber = 0;
|
private int _controllerNumber;
|
||||||
private string _controllerImage;
|
private string _controllerImage;
|
||||||
private int _device;
|
private int _device;
|
||||||
private object _configuration;
|
private object _configuration;
|
||||||
private string _profileName;
|
private string _profileName;
|
||||||
private bool _isLoaded;
|
private bool _isLoaded;
|
||||||
private readonly UserControl _owner;
|
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
||||||
public IGamepad SelectedGamepad { get; private set; }
|
public IGamepad SelectedGamepad { get; private set; }
|
||||||
@@ -176,11 +176,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
SvgImage image = new SvgImage();
|
SvgImage image = new();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(_controllerImage))
|
if (!string.IsNullOrWhiteSpace(_controllerImage))
|
||||||
{
|
{
|
||||||
SvgSource source = new SvgSource();
|
SvgSource source = new();
|
||||||
|
|
||||||
source.Load(EmbeddedResources.GetStream(_controllerImage));
|
source.Load(EmbeddedResources.GetStream(_controllerImage));
|
||||||
|
|
||||||
@@ -234,22 +234,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public ControllerInputViewModel(UserControl owner) : this()
|
public ControllerInputViewModel(UserControl owner) : this()
|
||||||
{
|
{
|
||||||
_owner = owner;
|
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
_mainWindow =
|
_mainWindow =
|
||||||
(MainWindow)((IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current
|
(MainWindow)((IClassicDesktopStyleApplicationLifetime)Application.Current
|
||||||
.ApplicationLifetime).MainWindow;
|
.ApplicationLifetime).MainWindow;
|
||||||
|
|
||||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
||||||
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||||
if (_mainWindow.ViewModel.AppHost != null)
|
|
||||||
{
|
_mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
||||||
_mainWindow.ViewModel.AppHost.NpadManager.BlockInputUpdates();
|
|
||||||
}
|
|
||||||
|
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
|
|
||||||
@@ -351,7 +347,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (type == DeviceType.Keyboard)
|
|
||||||
|
if (type == DeviceType.Keyboard)
|
||||||
{
|
{
|
||||||
if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver)
|
if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver)
|
||||||
{
|
{
|
||||||
@@ -448,7 +445,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
const string Hyphen = "-";
|
const string Hyphen = "-";
|
||||||
const int Offset = 1;
|
const int Offset = 1;
|
||||||
|
|
||||||
return str.Substring(str.IndexOf(Hyphen) + Offset);
|
return str[(str.IndexOf(Hyphen) + Offset)..];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadDevices()
|
public void LoadDevices()
|
||||||
@@ -562,7 +559,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ButtonL = Key.E,
|
ButtonL = Key.E,
|
||||||
ButtonZl = Key.Q,
|
ButtonZl = Key.Q,
|
||||||
ButtonSl = Key.Unbound,
|
ButtonSl = Key.Unbound,
|
||||||
ButtonSr = Key.Unbound
|
ButtonSr = Key.Unbound,
|
||||||
},
|
},
|
||||||
LeftJoyconStick =
|
LeftJoyconStick =
|
||||||
new JoyconConfigKeyboardStick<Key>
|
new JoyconConfigKeyboardStick<Key>
|
||||||
@@ -571,7 +568,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
StickDown = Key.S,
|
StickDown = Key.S,
|
||||||
StickLeft = Key.A,
|
StickLeft = Key.A,
|
||||||
StickRight = Key.D,
|
StickRight = Key.D,
|
||||||
StickButton = Key.F
|
StickButton = Key.F,
|
||||||
},
|
},
|
||||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||||
{
|
{
|
||||||
@@ -583,7 +580,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ButtonR = Key.U,
|
ButtonR = Key.U,
|
||||||
ButtonZr = Key.O,
|
ButtonZr = Key.O,
|
||||||
ButtonSl = Key.Unbound,
|
ButtonSl = Key.Unbound,
|
||||||
ButtonSr = Key.Unbound
|
ButtonSr = Key.Unbound,
|
||||||
},
|
},
|
||||||
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
{
|
{
|
||||||
@@ -591,8 +588,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
StickDown = Key.K,
|
StickDown = Key.K,
|
||||||
StickLeft = Key.J,
|
StickLeft = Key.J,
|
||||||
StickRight = Key.L,
|
StickRight = Key.L,
|
||||||
StickButton = Key.H
|
StickButton = Key.H,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (activeDevice.Type == DeviceType.Controller)
|
else if (activeDevice.Type == DeviceType.Controller)
|
||||||
@@ -622,14 +619,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||||
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
},
|
},
|
||||||
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
{
|
{
|
||||||
Joystick = ConfigStickInputId.Left,
|
Joystick = ConfigStickInputId.Left,
|
||||||
StickButton = ConfigGamepadInputId.LeftStick,
|
StickButton = ConfigGamepadInputId.LeftStick,
|
||||||
InvertStickX = false,
|
InvertStickX = false,
|
||||||
InvertStickY = false
|
InvertStickY = false,
|
||||||
},
|
},
|
||||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
{
|
{
|
||||||
@@ -641,28 +638,28 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ButtonR = ConfigGamepadInputId.RightShoulder,
|
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||||
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
},
|
},
|
||||||
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
{
|
{
|
||||||
Joystick = ConfigStickInputId.Right,
|
Joystick = ConfigStickInputId.Right,
|
||||||
StickButton = ConfigGamepadInputId.RightStick,
|
StickButton = ConfigGamepadInputId.RightStick,
|
||||||
InvertStickX = false,
|
InvertStickX = false,
|
||||||
InvertStickY = false
|
InvertStickY = false,
|
||||||
},
|
},
|
||||||
Motion = new StandardMotionConfigController
|
Motion = new StandardMotionConfigController
|
||||||
{
|
{
|
||||||
MotionBackend = MotionInputBackendType.GamepadDriver,
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||||
EnableMotion = true,
|
EnableMotion = true,
|
||||||
Sensitivity = 100,
|
Sensitivity = 100,
|
||||||
GyroDeadzone = 1
|
GyroDeadzone = 1,
|
||||||
},
|
},
|
||||||
Rumble = new RumbleConfigController
|
Rumble = new RumbleConfigController
|
||||||
{
|
{
|
||||||
StrongRumble = 1f,
|
StrongRumble = 1f,
|
||||||
WeakRumble = 1f,
|
WeakRumble = 1f,
|
||||||
EnableRumble = false
|
EnableRumble = false,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -709,7 +706,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
|
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
||||||
}
|
}
|
||||||
catch (JsonException) { }
|
catch (JsonException) { }
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
@@ -754,8 +751,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
|
bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
|
||||||
|
|
||||||
if (validFileName)
|
if (validFileName)
|
||||||
@@ -775,7 +771,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
config.ControllerType = Controllers[_controller].Type;
|
config.ControllerType = Controllers[_controller].Type;
|
||||||
|
|
||||||
string jsonString = JsonHelper.Serialize(config, SerializerContext.InputConfig);
|
string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
|
||||||
|
|
||||||
await File.WriteAllTextAsync(path, jsonString);
|
await File.WriteAllTextAsync(path, jsonString);
|
||||||
|
|
||||||
@@ -786,7 +782,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async void RemoveProfile()
|
public async void RemoveProfile()
|
||||||
{
|
{
|
||||||
@@ -887,6 +882,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected;
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
@@ -22,6 +22,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Application = Avalonia.Application;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
@@ -31,16 +32,15 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
|
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
|
||||||
private readonly string _downloadableContentJsonPath;
|
private readonly string _downloadableContentJsonPath;
|
||||||
|
|
||||||
private VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private AvaloniaList<DownloadableContentModel> _downloadableContents = new();
|
private AvaloniaList<DownloadableContentModel> _downloadableContents = new();
|
||||||
private AvaloniaList<DownloadableContentModel> _views = new();
|
private AvaloniaList<DownloadableContentModel> _views = new();
|
||||||
private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new();
|
private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new();
|
||||||
|
|
||||||
private string _search;
|
private string _search;
|
||||||
private ulong _titleId;
|
private readonly ulong _titleId;
|
||||||
private string _titleName;
|
|
||||||
|
|
||||||
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public AvaloniaList<DownloadableContentModel> DownloadableContents
|
public AvaloniaList<DownloadableContentModel> DownloadableContents
|
||||||
{
|
{
|
||||||
@@ -90,18 +90,24 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
|
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
public IStorageProvider StorageProvider;
|
||||||
|
|
||||||
|
public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
|
||||||
_titleId = titleId;
|
_titleId = titleId;
|
||||||
_titleName = titleName;
|
|
||||||
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
StorageProvider = desktop.MainWindow.StorageProvider;
|
||||||
|
}
|
||||||
|
|
||||||
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
|
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, SerializerContext.ListDownloadableContentContainer);
|
_downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, _serializerContext.ListDownloadableContentContainer);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -196,29 +202,24 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public async void Add()
|
public async void Add()
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new OpenFileDialog()
|
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
|
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
|
||||||
AllowMultiple = true
|
AllowMultiple = true,
|
||||||
};
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter
|
|
||||||
{
|
{
|
||||||
Name = "NSP",
|
new("NSP")
|
||||||
Extensions = { "nsp" }
|
{
|
||||||
|
Patterns = new[] { "*.nsp" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nsp" }
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
foreach (var file in result)
|
||||||
{
|
{
|
||||||
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
await AddDownloadableContent(file.Path.LocalPath);
|
||||||
|
|
||||||
if (files != null)
|
|
||||||
{
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
await AddDownloadableContent(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +315,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
container = new DownloadableContentContainer
|
container = new DownloadableContentContainer
|
||||||
{
|
{
|
||||||
ContainerPath = downloadableContent.ContainerPath,
|
ContainerPath = downloadableContent.ContainerPath,
|
||||||
DownloadableContentNcaList = new List<DownloadableContentNca>()
|
DownloadableContentNcaList = new List<DownloadableContentNca>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +323,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
Enabled = downloadableContent.Enabled,
|
Enabled = downloadableContent.Enabled,
|
||||||
TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16),
|
TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16),
|
||||||
FullPath = downloadableContent.FullPath
|
FullPath = downloadableContent.FullPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +332,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
_downloadableContentContainerList.Add(container);
|
_downloadableContentContainerList.Add(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, SerializerContext.ListDownloadableContentContainer);
|
JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
@@ -12,6 +14,7 @@ using Ryujinx.Ava.Input;
|
|||||||
using Ryujinx.Ava.UI.Controls;
|
using Ryujinx.Ava.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
using Ryujinx.Ava.UI.Models.Generic;
|
||||||
using Ryujinx.Ava.UI.Renderer;
|
using Ryujinx.Ava.UI.Renderer;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
@@ -23,6 +26,7 @@ using Ryujinx.HLE.FileSystem;
|
|||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.Ui;
|
using Ryujinx.HLE.Ui;
|
||||||
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
@@ -34,7 +38,10 @@ using System.Collections.ObjectModel;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Path = System.IO.Path;
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
|
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||||
|
using Key = Ryujinx.Input.Key;
|
||||||
|
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||||
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
@@ -89,7 +96,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private Cursor _cursor;
|
private Cursor _cursor;
|
||||||
private string _title;
|
private string _title;
|
||||||
private string _currentEmulatedGamePath;
|
private string _currentEmulatedGamePath;
|
||||||
private AutoResetEvent _rendererWaitEvent;
|
private readonly AutoResetEvent _rendererWaitEvent;
|
||||||
private WindowState _windowState;
|
private WindowState _windowState;
|
||||||
private double _windowWidth;
|
private double _windowWidth;
|
||||||
private double _windowHeight;
|
private double _windowHeight;
|
||||||
@@ -99,8 +106,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public ApplicationData ListSelectedApplication;
|
public ApplicationData ListSelectedApplication;
|
||||||
public ApplicationData GridSelectedApplication;
|
public ApplicationData GridSelectedApplication;
|
||||||
|
|
||||||
public event Action ReloadGameList;
|
|
||||||
|
|
||||||
private string TitleName { get; set; }
|
private string TitleName { get; set; }
|
||||||
internal AppHost AppHost { get; set; }
|
internal AppHost AppHost { get; set; }
|
||||||
|
|
||||||
@@ -125,10 +130,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void Initialize(
|
public void Initialize(
|
||||||
ContentManager contentManager,
|
ContentManager contentManager,
|
||||||
|
IStorageProvider storageProvider,
|
||||||
ApplicationLibrary applicationLibrary,
|
ApplicationLibrary applicationLibrary,
|
||||||
VirtualFileSystem virtualFileSystem,
|
VirtualFileSystem virtualFileSystem,
|
||||||
AccountManager accountManager,
|
AccountManager accountManager,
|
||||||
Ryujinx.Input.HLE.InputManager inputManager,
|
InputManager inputManager,
|
||||||
UserChannelPersistence userChannelPersistence,
|
UserChannelPersistence userChannelPersistence,
|
||||||
LibHacHorizonManager libHacHorizonManager,
|
LibHacHorizonManager libHacHorizonManager,
|
||||||
IHostUiHandler uiHandler,
|
IHostUiHandler uiHandler,
|
||||||
@@ -138,6 +144,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
TopLevel topLevel)
|
TopLevel topLevel)
|
||||||
{
|
{
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
StorageProvider = storageProvider;
|
||||||
ApplicationLibrary = applicationLibrary;
|
ApplicationLibrary = applicationLibrary;
|
||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
AccountManager = accountManager;
|
AccountManager = accountManager;
|
||||||
@@ -177,7 +184,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public bool CanUpdate
|
public bool CanUpdate
|
||||||
{
|
{
|
||||||
get => _canUpdate && EnableNonGameRunningControls && Modules.Updater.CanUpdate(false);
|
get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_canUpdate = value;
|
_canUpdate = value;
|
||||||
@@ -343,11 +350,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OpenUserSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
public bool OpenUserSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||||
|
|
||||||
public bool OpenDeviceSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
|
public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||||
|
|
||||||
public bool OpenBcatSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||||
|
|
||||||
public string LoadHeading
|
public string LoadHeading
|
||||||
{
|
{
|
||||||
@@ -885,10 +892,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ContentManager ContentManager { get; private set; }
|
public ContentManager ContentManager { get; private set; }
|
||||||
|
public IStorageProvider StorageProvider { get; private set; }
|
||||||
public ApplicationLibrary ApplicationLibrary { get; private set; }
|
public ApplicationLibrary ApplicationLibrary { get; private set; }
|
||||||
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
public VirtualFileSystem VirtualFileSystem { get; private set; }
|
||||||
public AccountManager AccountManager { get; private set; }
|
public AccountManager AccountManager { get; private set; }
|
||||||
public Ryujinx.Input.HLE.InputManager InputManager { get; private set; }
|
public InputManager InputManager { get; private set; }
|
||||||
public UserChannelPersistence UserChannelPersistence { get; private set; }
|
public UserChannelPersistence UserChannelPersistence { get; private set; }
|
||||||
public Action<bool> ShowLoading { get; private set; }
|
public Action<bool> ShowLoading { get; private set; }
|
||||||
public Action<bool> SwitchToGameControl { get; private set; }
|
public Action<bool> SwitchToGameControl { get; private set; }
|
||||||
@@ -919,7 +927,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
return SortMode switch
|
return SortMode switch
|
||||||
{
|
{
|
||||||
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
|
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
|
||||||
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes)
|
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSizeBytes)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSizeBytes),
|
||||||
ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum)
|
ApplicationSort.TotalTimePlayed => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TimePlayedNum)
|
||||||
@@ -935,6 +944,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
||||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
||||||
_ => null,
|
_ => null,
|
||||||
|
#pragma warning restore IDE0055
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,7 +1033,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
// Purge Applet Cache.
|
// Purge Applet Cache.
|
||||||
|
|
||||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||||
|
|
||||||
if (miiEditorCacheFolder.Exists)
|
if (miiEditorCacheFolder.Exists)
|
||||||
{
|
{
|
||||||
@@ -1044,18 +1054,21 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
RefreshFirmwareStatus();
|
RefreshFirmwareStatus();
|
||||||
}
|
}
|
||||||
}) { Name = "GUI.FirmwareInstallerThread" };
|
})
|
||||||
|
{
|
||||||
|
Name = "GUI.FirmwareInstallerThread",
|
||||||
|
};
|
||||||
|
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (LibHac.Common.Keys.MissingKeyException ex)
|
catch (MissingKeyException ex)
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
||||||
|
|
||||||
async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, (desktop.MainWindow as MainWindow));
|
static async void Action() => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys);
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(Action);
|
Dispatcher.UIThread.Post(Action);
|
||||||
}
|
}
|
||||||
@@ -1120,7 +1133,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private void PrepareLoadScreen()
|
private void PrepareLoadScreen()
|
||||||
{
|
{
|
||||||
using MemoryStream stream = new(SelectedIcon);
|
using MemoryStream stream = new(SelectedIcon);
|
||||||
using var gameIconBmp = SixLabors.ImageSharp.Image.Load<Bgra32>(stream);
|
using var gameIconBmp = Image.Load<Bgra32>(stream);
|
||||||
|
|
||||||
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
|
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
|
||||||
|
|
||||||
@@ -1175,9 +1188,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
Avalonia.Application.Current.Styles.TryGetResource(args.VSyncEnabled
|
Application.Current.Styles.TryGetResource(args.VSyncEnabled
|
||||||
? "VsyncEnabled"
|
? "VsyncEnabled"
|
||||||
: "VsyncDisabled", out object color);
|
: "VsyncDisabled",
|
||||||
|
Avalonia.Application.Current.ActualThemeVariant,
|
||||||
|
out object color);
|
||||||
|
|
||||||
if (color is not null)
|
if (color is not null)
|
||||||
{
|
{
|
||||||
@@ -1208,7 +1223,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
#region PublicMethods
|
#region PublicMethods
|
||||||
|
|
||||||
public void SetUIProgressHandlers(Switch emulationContext)
|
public void SetUiProgressHandlers(Switch emulationContext)
|
||||||
{
|
{
|
||||||
if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null)
|
if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null)
|
||||||
{
|
{
|
||||||
@@ -1222,17 +1237,17 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void LoadConfigurableHotKeys()
|
public void LoadConfigurableHotKeys()
|
||||||
{
|
{
|
||||||
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey))
|
||||||
{
|
{
|
||||||
ShowUiKey = new KeyGesture(showUiKey);
|
ShowUiKey = new KeyGesture(showUiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
||||||
{
|
{
|
||||||
ScreenshotKey = new KeyGesture(screenshotKey);
|
ScreenshotKey = new KeyGesture(screenshotKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
||||||
{
|
{
|
||||||
PauseKey = new KeyGesture(pauseKey);
|
PauseKey = new KeyGesture(pauseKey);
|
||||||
}
|
}
|
||||||
@@ -1248,6 +1263,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
ShowMenuAndStatusBar = false;
|
ShowMenuAndStatusBar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ToggleStartGamesInFullscreen()
|
||||||
|
{
|
||||||
|
StartGamesInFullscreen = !StartGamesInFullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleShowConsole()
|
||||||
|
{
|
||||||
|
ShowConsole = !ShowConsole;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetListMode()
|
public void SetListMode()
|
||||||
{
|
{
|
||||||
Glyph = Glyph.List;
|
Glyph = Glyph.List;
|
||||||
@@ -1260,43 +1285,57 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public async void InstallFirmwareFromFile()
|
public async void InstallFirmwareFromFile()
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new() { AllowMultiple = false };
|
AllowMultiple = false,
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } });
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
|
|
||||||
|
|
||||||
string[] file = await dialog.ShowAsync(desktop.MainWindow);
|
|
||||||
|
|
||||||
if (file != null && file.Length > 0)
|
|
||||||
{
|
{
|
||||||
await HandleFirmwareInstallation(file[0]);
|
new(LocaleManager.Instance[LocaleKeys.FileDialogAllTypes])
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.xci", "*.zip" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci", "public.zip-archive" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-xci", "application/zip" }
|
||||||
|
},
|
||||||
|
new("XCI")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.xci" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-xci" }
|
||||||
|
},
|
||||||
|
new("ZIP")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.zip" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "public.zip-archive" },
|
||||||
|
MimeTypes = new[] { "application/zip" }
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.Count > 0)
|
||||||
|
{
|
||||||
|
await HandleFirmwareInstallation(result[0].Path.LocalPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void InstallFirmwareFromFolder()
|
public async void InstallFirmwareFromFolder()
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||||
{
|
{
|
||||||
OpenFolderDialog dialog = new();
|
AllowMultiple = false
|
||||||
|
});
|
||||||
|
|
||||||
string folder = await dialog.ShowAsync(desktop.MainWindow);
|
if (result.Count > 0)
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(folder))
|
|
||||||
{
|
{
|
||||||
await HandleFirmwareInstallation(folder);
|
await HandleFirmwareInstallation(result[0].Path.LocalPath);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenRyujinxFolder()
|
public void OpenRyujinxFolder()
|
||||||
{
|
{
|
||||||
OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
|
OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenLogsFolder()
|
public void OpenLogsFolder()
|
||||||
{
|
{
|
||||||
string logPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs");
|
string logPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs");
|
||||||
|
|
||||||
@@ -1327,7 +1366,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeLanguage(object languageCode)
|
public static void ChangeLanguage(object languageCode)
|
||||||
{
|
{
|
||||||
LocaleManager.Instance.LoadLanguage((string)languageCode);
|
LocaleManager.Instance.LoadLanguage((string)languageCode);
|
||||||
|
|
||||||
@@ -1338,23 +1377,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleFileType(string fileType)
|
|
||||||
{
|
|
||||||
_ = fileType switch
|
|
||||||
{
|
|
||||||
"NSP" => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP,
|
|
||||||
"PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0,
|
|
||||||
"XCI" => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI,
|
|
||||||
"NCA" => ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NCA,
|
|
||||||
"NRO" => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO,
|
|
||||||
"NSO" => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(fileType),
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
|
||||||
LoadApplications();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void ManageProfiles()
|
public async void ManageProfiles()
|
||||||
{
|
{
|
||||||
await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
|
await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
|
||||||
@@ -1365,76 +1387,84 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
AppHost.Device.System.SimulateWakeUpMessage();
|
AppHost.Device.System.SimulateWakeUpMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void LoadApplications()
|
|
||||||
{
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
Applications.Clear();
|
|
||||||
|
|
||||||
StatusBarVisible = true;
|
|
||||||
StatusBarProgressMaximum = 0;
|
|
||||||
StatusBarProgressValue = 0;
|
|
||||||
|
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
ReloadGameList?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void OpenFile()
|
public async void OpenFile()
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new()
|
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
|
||||||
|
AllowMultiple = false,
|
||||||
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle]
|
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
|
||||||
};
|
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter
|
|
||||||
{
|
{
|
||||||
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
|
Patterns = new[] { "*.nsp", "*.xci", "*.nca", "*.nro", "*.nso" },
|
||||||
Extensions =
|
AppleUniformTypeIdentifiers = new[]
|
||||||
{
|
{
|
||||||
"nsp",
|
"com.ryujinx.nsp",
|
||||||
"pfs0",
|
"com.ryujinx.xci",
|
||||||
"xci",
|
"com.ryujinx.nca",
|
||||||
"nca",
|
"com.ryujinx.nro",
|
||||||
"nro",
|
"com.ryujinx.nso"
|
||||||
"nso"
|
},
|
||||||
|
MimeTypes = new[]
|
||||||
|
{
|
||||||
|
"application/x-nx-nsp",
|
||||||
|
"application/x-nx-xci",
|
||||||
|
"application/x-nx-nca",
|
||||||
|
"application/x-nx-nro",
|
||||||
|
"application/x-nx-nso"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new("NSP")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.nsp" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nsp" }
|
||||||
|
},
|
||||||
|
new("XCI")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.xci" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-xci" }
|
||||||
|
},
|
||||||
|
new("NCA")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.nca" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nca" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nca" }
|
||||||
|
},
|
||||||
|
new("NRO")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.nro" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nro" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nro" }
|
||||||
|
},
|
||||||
|
new("NSO")
|
||||||
|
{
|
||||||
|
Patterns = new[] { "*.nso" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nso" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nso" }
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
|
if (result.Count > 0)
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } });
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
|
|
||||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
|
|
||||||
|
|
||||||
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
|
||||||
|
|
||||||
if (files != null && files.Length > 0)
|
|
||||||
{
|
{
|
||||||
LoadApplication(files[0]);
|
LoadApplication(result[0].Path.LocalPath);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OpenFolder()
|
public async void OpenFolder()
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||||
{
|
{
|
||||||
OpenFolderDialog dialog = new()
|
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
|
||||||
{
|
AllowMultiple = false
|
||||||
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle]
|
});
|
||||||
};
|
|
||||||
|
|
||||||
string folder = await dialog.ShowAsync(desktop.MainWindow);
|
if (result.Count > 0)
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(folder) && Directory.Exists(folder))
|
|
||||||
{
|
{
|
||||||
LoadApplication(folder);
|
LoadApplication(result[0].Path.LocalPath);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1458,10 +1488,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
Logger.RestartTime();
|
Logger.RestartTime();
|
||||||
|
|
||||||
if (SelectedIcon == null)
|
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path);
|
||||||
{
|
|
||||||
SelectedIcon = ApplicationLibrary.GetApplicationIcon(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrepareLoadScreen();
|
PrepareLoadScreen();
|
||||||
|
|
||||||
@@ -1521,7 +1548,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGameMetadata(string titleId)
|
public static void UpdateGameMetadata(string titleId)
|
||||||
{
|
{
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DynamicData;
|
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
using Ryujinx.Audio.Backends.SDL2;
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
@@ -18,13 +17,13 @@ using Ryujinx.HLE.FileSystem;
|
|||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
@@ -45,7 +44,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private float _volume;
|
private float _volume;
|
||||||
private bool _isVulkanAvailable = true;
|
private bool _isVulkanAvailable = true;
|
||||||
private bool _directoryChanged;
|
private bool _directoryChanged;
|
||||||
private List<string> _gpuIds = new();
|
private readonly List<string> _gpuIds = new();
|
||||||
private KeyboardHotkeys _keyboardHotkeys;
|
private KeyboardHotkeys _keyboardHotkeys;
|
||||||
private int _graphicsBackendIndex;
|
private int _graphicsBackendIndex;
|
||||||
private string _customThemePath;
|
private string _customThemePath;
|
||||||
@@ -146,6 +145,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public bool EnableShaderCache { get; set; }
|
public bool EnableShaderCache { get; set; }
|
||||||
public bool EnableTextureRecompression { get; set; }
|
public bool EnableTextureRecompression { get; set; }
|
||||||
public bool EnableMacroHLE { get; set; }
|
public bool EnableMacroHLE { get; set; }
|
||||||
|
public bool EnableColorSpacePassthrough { get; set; }
|
||||||
public bool EnableFileLog { get; set; }
|
public bool EnableFileLog { get; set; }
|
||||||
public bool EnableStub { get; set; }
|
public bool EnableStub { get; set; }
|
||||||
public bool EnableInfo { get; set; }
|
public bool EnableInfo { get; set; }
|
||||||
@@ -248,7 +248,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public AvaloniaList<string> NetworkInterfaceList
|
public AvaloniaList<string> NetworkInterfaceList
|
||||||
{
|
{
|
||||||
get => new AvaloniaList<string>(_networkInterfaces.Keys);
|
get => new(_networkInterfaces.Keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardHotkeys KeyboardHotkeys
|
public KeyboardHotkeys KeyboardHotkeys
|
||||||
@@ -278,7 +278,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
LoadTimeZones();
|
Task.Run(LoadTimeZones);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,27 +290,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
_validTzRegions = new List<string>();
|
_validTzRegions = new List<string>();
|
||||||
_networkInterfaces = new Dictionary<string, string>();
|
_networkInterfaces = new Dictionary<string, string>();
|
||||||
|
|
||||||
CheckSoundBackends();
|
Task.Run(CheckSoundBackends);
|
||||||
PopulateNetworkInterfaces();
|
Task.Run(PopulateNetworkInterfaces);
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
LoadAvailableGpus();
|
Task.Run(LoadAvailableGpus);
|
||||||
LoadCurrentConfiguration();
|
LoadCurrentConfiguration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckSoundBackends()
|
public async Task CheckSoundBackends()
|
||||||
{
|
{
|
||||||
IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported;
|
IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported;
|
||||||
IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported;
|
IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported;
|
||||||
IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
|
IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
|
||||||
|
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsOpenAlEnabled));
|
||||||
|
OnPropertyChanged(nameof(IsSoundIoEnabled));
|
||||||
|
OnPropertyChanged(nameof(IsSDL2Enabled));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadAvailableGpus()
|
private async Task LoadAvailableGpus()
|
||||||
{
|
{
|
||||||
_gpuIds = new List<string>();
|
AvailableGpus.Clear();
|
||||||
List<string> names = new();
|
|
||||||
var devices = VulkanRenderer.GetPhysicalDevices();
|
var devices = VulkanRenderer.GetPhysicalDevices();
|
||||||
|
|
||||||
if (devices.Length == 0)
|
if (devices.Length == 0)
|
||||||
@@ -321,17 +328,24 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var device in devices)
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
_gpuIds.Add(device.Id);
|
_gpuIds.Add(device.Id);
|
||||||
names.Add($"{device.Name} {(device.IsDiscrete ? "(dGPU)" : "")}");
|
|
||||||
|
AvailableGpus.Add(new ComboBoxItem { Content = $"{device.Name} {(device.IsDiscrete ? "(dGPU)" : "")}" });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AvailableGpus.Clear();
|
// GPU configuration needs to be loaded during the async method or it will always return 0.
|
||||||
AvailableGpus.AddRange(names.Select(x => new ComboBoxItem { Content = x }));
|
PreferredGpuIndex = _gpuIds.Contains(ConfigurationState.Instance.Graphics.PreferredGpu) ?
|
||||||
|
_gpuIds.IndexOf(ConfigurationState.Instance.Graphics.PreferredGpu) : 0;
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadTimeZones()
|
public async Task LoadTimeZones()
|
||||||
{
|
{
|
||||||
_timeZoneContentManager = new TimeZoneContentManager();
|
_timeZoneContentManager = new TimeZoneContentManager();
|
||||||
|
|
||||||
@@ -344,21 +358,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr;
|
string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr;
|
||||||
|
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2));
|
TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2));
|
||||||
|
|
||||||
_validTzRegions.Add(location);
|
_validTzRegions.Add(location);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateNetworkInterfaces()
|
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(TimeZone)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PopulateNetworkInterfaces()
|
||||||
{
|
{
|
||||||
_networkInterfaces.Clear();
|
_networkInterfaces.Clear();
|
||||||
_networkInterfaces.Add(LocaleManager.Instance[LocaleKeys.NetworkInterfaceDefault], "0");
|
_networkInterfaces.Add(LocaleManager.Instance[LocaleKeys.NetworkInterfaceDefault], "0");
|
||||||
|
|
||||||
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
|
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||||
|
{
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
_networkInterfaces.Add(networkInterface.Name, networkInterface.Id);
|
_networkInterfaces.Add(networkInterface.Name, networkInterface.Id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Network interface index needs to be loaded during the async method or it will always return 0.
|
||||||
|
NetworkInterfaceIndex = _networkInterfaces.Values.ToList().IndexOf(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(NetworkInterfaceIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ValidateAndSetTimeZone(string location)
|
public void ValidateAndSetTimeZone(string location)
|
||||||
@@ -416,10 +443,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value;
|
GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value;
|
||||||
PreferredGpuIndex = _gpuIds.Contains(config.Graphics.PreferredGpu) ? _gpuIds.IndexOf(config.Graphics.PreferredGpu) : 0;
|
// Physical devices are queried asynchronously hence the prefered index config value is loaded in LoadAvailableGpus().
|
||||||
EnableShaderCache = config.Graphics.EnableShaderCache;
|
EnableShaderCache = config.Graphics.EnableShaderCache;
|
||||||
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
||||||
EnableMacroHLE = config.Graphics.EnableMacroHLE;
|
EnableMacroHLE = config.Graphics.EnableMacroHLE;
|
||||||
|
EnableColorSpacePassthrough = config.Graphics.EnableColorSpacePassthrough;
|
||||||
ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1;
|
ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1;
|
||||||
CustomResolutionScale = config.Graphics.ResScaleCustom;
|
CustomResolutionScale = config.Graphics.ResScaleCustom;
|
||||||
MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy));
|
MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy));
|
||||||
@@ -436,6 +464,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
// Network
|
// Network
|
||||||
EnableInternetAccess = config.System.EnableInternetAccess;
|
EnableInternetAccess = config.System.EnableInternetAccess;
|
||||||
|
// LAN interface index is loaded asynchronously in PopulateNetworkInterfaces()
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
EnableFileLog = config.Logger.EnableFileLog;
|
EnableFileLog = config.Logger.EnableFileLog;
|
||||||
@@ -449,8 +478,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
EnableFsAccessLog = config.Logger.EnableFsAccessLog;
|
EnableFsAccessLog = config.Logger.EnableFsAccessLog;
|
||||||
FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode;
|
FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode;
|
||||||
OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value;
|
OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value;
|
||||||
|
|
||||||
NetworkInterfaceIndex = _networkInterfaces.Values.ToList().IndexOf(config.Multiplayer.LanInterfaceId.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveSettings()
|
public void SaveSettings()
|
||||||
@@ -507,6 +534,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
||||||
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
||||||
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
|
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
|
||||||
|
config.Graphics.EnableColorSpacePassthrough.Value = EnableColorSpacePassthrough;
|
||||||
config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1;
|
config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1;
|
||||||
config.Graphics.ResScaleCustom.Value = CustomResolutionScale;
|
config.Graphics.ResScaleCustom.Value = CustomResolutionScale;
|
||||||
config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy);
|
config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy);
|
||||||
@@ -561,7 +589,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
_directoryChanged = false;
|
_directoryChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RevertIfNotSaved()
|
private static void RevertIfNotSaved()
|
||||||
{
|
{
|
||||||
Program.ReloadConfig();
|
Program.ReloadConfig();
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
@@ -16,7 +17,6 @@ using Ryujinx.Common.Configuration;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -29,17 +29,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
public class TitleUpdateViewModel : BaseModel
|
public class TitleUpdateViewModel : BaseModel
|
||||||
{
|
{
|
||||||
public TitleUpdateMetadata _titleUpdateWindowData;
|
public TitleUpdateMetadata TitleUpdateWindowData;
|
||||||
public readonly string _titleUpdateJsonPath;
|
public readonly string TitleUpdateJsonPath;
|
||||||
private VirtualFileSystem _virtualFileSystem { get; }
|
private VirtualFileSystem VirtualFileSystem { get; }
|
||||||
private ulong _titleId { get; }
|
private ulong TitleId { get; }
|
||||||
private string _titleName { get; }
|
|
||||||
|
|
||||||
private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
|
private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
|
||||||
private AvaloniaList<object> _views = new();
|
private AvaloniaList<object> _views = new();
|
||||||
private object _selectedUpdate;
|
private object _selectedUpdate;
|
||||||
|
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public AvaloniaList<TitleUpdateModel> TitleUpdates
|
public AvaloniaList<TitleUpdateModel> TitleUpdates
|
||||||
{
|
{
|
||||||
@@ -71,27 +70,33 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
public IStorageProvider StorageProvider;
|
||||||
|
|
||||||
|
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
|
|
||||||
_titleId = titleId;
|
TitleId = titleId;
|
||||||
_titleName = titleName;
|
|
||||||
|
|
||||||
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
StorageProvider = desktop.MainWindow.StorageProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_titleUpdateJsonPath, SerializerContext.TitleUpdateMetadata);
|
TitleUpdateWindowData = JsonHelper.DeserializeFromFile(TitleUpdateJsonPath, _serializerContext.TitleUpdateMetadata);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}");
|
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}");
|
||||||
|
|
||||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
TitleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
Selected = "",
|
Selected = "",
|
||||||
Paths = new List<string>()
|
Paths = new List<string>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
@@ -102,12 +107,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private void LoadUpdates()
|
private void LoadUpdates()
|
||||||
{
|
{
|
||||||
foreach (string path in _titleUpdateWindowData.Paths)
|
foreach (string path in TitleUpdateWindowData.Paths)
|
||||||
{
|
{
|
||||||
AddUpdate(path);
|
AddUpdate(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
|
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == TitleUpdateWindowData.Selected, null);
|
||||||
|
|
||||||
SelectedUpdate = selected;
|
SelectedUpdate = selected;
|
||||||
|
|
||||||
@@ -126,7 +131,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
|
||||||
|
if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -163,7 +169,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
|
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, new PartitionFileSystem(file.AsStorage()), TitleId.ToString("x16"), 0);
|
||||||
|
|
||||||
if (controlNca != null && patchNca != null)
|
if (controlNca != null && patchNca != null)
|
||||||
{
|
{
|
||||||
@@ -203,29 +209,23 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public async void Add()
|
public async void Add()
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new()
|
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
|
AllowMultiple = true,
|
||||||
AllowMultiple = true
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
};
|
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter
|
|
||||||
{
|
{
|
||||||
Name = "NSP",
|
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
|
||||||
Extensions = { "nsp" }
|
{
|
||||||
|
Patterns = new[] { "*.nsp" },
|
||||||
|
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" },
|
||||||
|
MimeTypes = new[] { "application/x-nx-nsp" }
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
foreach (var file in result)
|
||||||
{
|
{
|
||||||
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
AddUpdate(file.Path.LocalPath);
|
||||||
|
|
||||||
if (files != null)
|
|
||||||
{
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
AddUpdate(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SortUpdates();
|
SortUpdates();
|
||||||
@@ -233,20 +233,20 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData.Paths.Clear();
|
TitleUpdateWindowData.Paths.Clear();
|
||||||
_titleUpdateWindowData.Selected = "";
|
TitleUpdateWindowData.Selected = "";
|
||||||
|
|
||||||
foreach (TitleUpdateModel update in TitleUpdates)
|
foreach (TitleUpdateModel update in TitleUpdates)
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData.Paths.Add(update.Path);
|
TitleUpdateWindowData.Paths.Add(update.Path);
|
||||||
|
|
||||||
if (update == SelectedUpdate)
|
if (update == SelectedUpdate)
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData.Selected = update.Path;
|
TitleUpdateWindowData.Selected = update.Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_titleUpdateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata);
|
JsonHelper.SerializeToFile(TitleUpdateJsonPath, TitleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -28,7 +28,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private Color _backgroundColor = Colors.White;
|
private Color _backgroundColor = Colors.White;
|
||||||
|
|
||||||
private int _selectedIndex;
|
private int _selectedIndex;
|
||||||
private byte[] _selectedImage;
|
|
||||||
|
|
||||||
public UserFirmwareAvatarSelectorViewModel()
|
public UserFirmwareAvatarSelectorViewModel()
|
||||||
{
|
{
|
||||||
@@ -78,11 +77,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] SelectedImage
|
public byte[] SelectedImage { get; private set; }
|
||||||
{
|
|
||||||
get => _selectedImage;
|
|
||||||
private set => _selectedImage = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadImagesFromStore()
|
private void LoadImagesFromStore()
|
||||||
{
|
{
|
||||||
@@ -110,12 +105,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||||
{
|
{
|
||||||
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
|
using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open);
|
||||||
{
|
|
||||||
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
@@ -128,9 +123,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
using (MemoryStream stream = new())
|
using MemoryStream stream = new();
|
||||||
using (MemoryStream streamPng = new())
|
using MemoryStream streamPng = new();
|
||||||
{
|
|
||||||
file.Get.AsStream().CopyTo(stream);
|
file.Get.AsStream().CopyTo(stream);
|
||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
@@ -144,13 +139,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] DecompressYaz0(Stream stream)
|
private static byte[] DecompressYaz0(Stream stream)
|
||||||
{
|
{
|
||||||
using (BinaryReader reader = new(stream))
|
using BinaryReader reader = new(stream);
|
||||||
{
|
|
||||||
reader.ReadInt32(); // Magic
|
reader.ReadInt32(); // Magic
|
||||||
|
|
||||||
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
||||||
@@ -227,4 +220,3 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
@@ -1,7 +1,7 @@
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public bool IsEmpty { get; set; }
|
public bool IsEmpty { get; set; }
|
||||||
|
|
||||||
public void Dispose() { }
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private string _search;
|
private string _search;
|
||||||
private ObservableCollection<SaveModel> _saves = new();
|
private ObservableCollection<SaveModel> _saves = new();
|
||||||
private ObservableCollection<SaveModel> _views = new();
|
private ObservableCollection<SaveModel> _views = new();
|
||||||
private AccountManager _accountManager;
|
private readonly AccountManager _accountManager;
|
||||||
|
|
||||||
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
|
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
|
||||||
|
|
||||||
@@ -102,19 +102,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private IComparer<SaveModel> GetComparer()
|
private IComparer<SaveModel> GetComparer()
|
||||||
{
|
{
|
||||||
switch (SortIndex)
|
return SortIndex switch
|
||||||
{
|
{
|
||||||
case 0:
|
0 => OrderIndex == 0
|
||||||
return OrderIndex == 0
|
|
||||||
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
|
||||||
: SortExpressionComparer<SaveModel>.Descending(save => save.Title);
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Title),
|
||||||
case 1:
|
1 => OrderIndex == 0
|
||||||
return OrderIndex == 0
|
|
||||||
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
|
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
|
||||||
: SortExpressionComparer<SaveModel>.Descending(save => save.Size);
|
: SortExpressionComparer<SaveModel>.Descending(save => save.Size),
|
||||||
default:
|
_ => null,
|
||||||
return null;
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,7 +14,6 @@
|
|||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView"
|
x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView"
|
||||||
x:DataType="viewModels:ControllerInputViewModel"
|
x:DataType="viewModels:ControllerInputViewModel"
|
||||||
x:CompileBindings="True"
|
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Focusable="True">
|
Focusable="True">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
@@ -66,7 +65,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
SelectionChanged="PlayerIndexBox_OnSelectionChanged"
|
SelectionChanged="PlayerIndexBox_OnSelectionChanged"
|
||||||
Items="{Binding PlayerIndexes}"
|
ItemsSource="{Binding PlayerIndexes}"
|
||||||
SelectedIndex="{Binding PlayerId}">
|
SelectedIndex="{Binding PlayerId}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@@ -94,15 +93,15 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{locale:Locale ControllerSettingsProfile}" />
|
Text="{locale:Locale ControllerSettingsProfile}" />
|
||||||
<ui:ComboBox
|
<ui:FAComboBox
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Name="ProfileBox"
|
Name="ProfileBox"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
SelectedIndex="0"
|
SelectedIndex="0"
|
||||||
Items="{Binding ProfilesList}"
|
ItemsSource="{Binding ProfilesList}"
|
||||||
Text="{Binding ProfileName}" />
|
Text="{Binding ProfileName, Mode=TwoWay}" />
|
||||||
<Button
|
<Button
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
@@ -170,7 +169,7 @@
|
|||||||
Name="DeviceBox"
|
Name="DeviceBox"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Items="{Binding DeviceList}"
|
ItemsSource="{Binding DeviceList}"
|
||||||
SelectedIndex="{Binding Device}" />
|
SelectedIndex="{Binding Device}" />
|
||||||
<Button
|
<Button
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
@@ -203,8 +202,8 @@
|
|||||||
<ComboBox
|
<ComboBox
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Items="{ReflectionBinding Controllers}"
|
ItemsSource="{Binding Controllers}"
|
||||||
SelectedIndex="{ReflectionBinding Controller}">
|
SelectedIndex="{Binding Controller}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate DataType="models:ControllerModel">
|
<DataTemplate DataType="models:ControllerModel">
|
||||||
<TextBlock Text="{Binding Name}" />
|
<TextBlock Text="{Binding Name}" />
|
||||||
@@ -723,7 +722,7 @@
|
|||||||
<Button
|
<Button
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Command="{ReflectionBinding ShowMotionConfig}">
|
Command="{Binding ShowMotionConfig}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -750,7 +749,7 @@
|
|||||||
<Button
|
<Button
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Command="{ReflectionBinding ShowRumbleConfig}">
|
Command="{Binding ShowRumbleConfig}">
|
||||||
<TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" />
|
<TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@@ -29,10 +29,9 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
|
|
||||||
foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
|
foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
|
||||||
{
|
{
|
||||||
if (visual is ToggleButton button && !(visual is CheckBox))
|
if (visual is ToggleButton button && visual is not CheckBox)
|
||||||
{
|
{
|
||||||
button.Checked += Button_Checked;
|
button.IsCheckedChanged += Button_IsCheckedChanged;
|
||||||
button.Unchecked += Button_Unchecked;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,9 +46,11 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Checked(object sender, RoutedEventArgs e)
|
private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is ToggleButton button)
|
if (sender is ToggleButton button)
|
||||||
|
{
|
||||||
|
if ((bool)button.IsChecked)
|
||||||
{
|
{
|
||||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
{
|
{
|
||||||
@@ -58,11 +59,11 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
|
|
||||||
bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
|
bool isStick = button.Tag != null && button.Tag.ToString() == "stick";
|
||||||
|
|
||||||
if (_currentAssigner == null && (bool)button.IsChecked)
|
if (_currentAssigner == null)
|
||||||
{
|
{
|
||||||
_currentAssigner = new ButtonKeyAssigner(button);
|
_currentAssigner = new ButtonKeyAssigner(button);
|
||||||
|
|
||||||
FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
|
this.Focus(NavigationMethod.Pointer);
|
||||||
|
|
||||||
PointerPressed += MouseClick;
|
PointerPressed += MouseClick;
|
||||||
|
|
||||||
@@ -91,6 +92,12 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentAssigner?.Cancel();
|
||||||
|
_currentAssigner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveCurrentProfile()
|
public void SaveCurrentProfile()
|
||||||
@@ -120,12 +127,6 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
return assigner;
|
return assigner;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_currentAssigner?.Cancel();
|
|
||||||
_currentAssigner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
bool shouldUnbind = false;
|
bool shouldUnbind = false;
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
|
x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
|
||||||
x:CompileBindings="True"
|
|
||||||
x:DataType="viewModels:MotionInputViewModel"
|
x:DataType="viewModels:MotionInputViewModel"
|
||||||
Focusable="True">
|
Focusable="True">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
|
@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
{
|
{
|
||||||
public partial class MotionInputView : UserControl
|
public partial class MotionInputView : UserControl
|
||||||
{
|
{
|
||||||
private MotionInputViewModel _viewModel;
|
private readonly MotionInputViewModel _viewModel;
|
||||||
|
|
||||||
public MotionInputView()
|
public MotionInputView()
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
MirrorInput = config.MirrorInput,
|
MirrorInput = config.MirrorInput,
|
||||||
Sensitivity = config.Sensitivity,
|
Sensitivity = config.Sensitivity,
|
||||||
GyroDeadzone = config.GyroDeadzone,
|
GyroDeadzone = config.GyroDeadzone,
|
||||||
EnableCemuHookMotion = config.EnableCemuHookMotion
|
EnableCemuHookMotion = config.EnableCemuHookMotion,
|
||||||
};
|
};
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -47,7 +47,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||||
SecondaryButtonText = "",
|
SecondaryButtonText = "",
|
||||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||||
Content = content
|
Content = content,
|
||||||
};
|
};
|
||||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||||
{
|
{
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
|
x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
|
||||||
x:DataType="viewModels:RumbleInputViewModel"
|
x:DataType="viewModels:RumbleInputViewModel"
|
||||||
x:CompileBindings="True"
|
|
||||||
Focusable="True">
|
Focusable="True">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
@@ -10,7 +10,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
{
|
{
|
||||||
public partial class RumbleInputView : UserControl
|
public partial class RumbleInputView : UserControl
|
||||||
{
|
{
|
||||||
private RumbleInputViewModel _viewModel;
|
private readonly RumbleInputViewModel _viewModel;
|
||||||
|
|
||||||
public RumbleInputView()
|
public RumbleInputView()
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
|||||||
_viewModel = new RumbleInputViewModel
|
_viewModel = new RumbleInputViewModel
|
||||||
{
|
{
|
||||||
StrongRumble = config.StrongRumble,
|
StrongRumble = config.StrongRumble,
|
||||||
WeakRumble = config.WeakRumble
|
WeakRumble = config.WeakRumble,
|
||||||
};
|
};
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@@ -7,8 +7,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
x:DataType="viewModels:MainWindowViewModel"
|
x:DataType="viewModels:MainWindowViewModel"
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView"
|
x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView">
|
||||||
x:CompileBindings="True">
|
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<viewModels:MainWindowViewModel />
|
<viewModels:MainWindowViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
@@ -25,12 +24,12 @@
|
|||||||
</Menu.ItemsPanel>
|
</Menu.ItemsPanel>
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding OpenFile}"
|
Command="{Binding OpenFile}"
|
||||||
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
Header="{locale:Locale MenuBarFileOpenFromFile}"
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding OpenFolder}"
|
Command="{Binding OpenFolder}"
|
||||||
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
Header="{locale:Locale MenuBarFileOpenUnpacked}"
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
|
||||||
@@ -42,11 +41,11 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding OpenRyujinxFolder}"
|
Command="{Binding OpenRyujinxFolder}"
|
||||||
Header="{locale:Locale MenuBarFileOpenEmuFolder}"
|
Header="{locale:Locale MenuBarFileOpenEmuFolder}"
|
||||||
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
|
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding OpenLogsFolder}"
|
Command="{Binding OpenLogsFolder}"
|
||||||
Header="{locale:Locale MenuBarFileOpenLogsFolder}"
|
Header="{locale:Locale MenuBarFileOpenLogsFolder}"
|
||||||
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
|
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
@@ -57,35 +56,75 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ToggleFullscreen}"
|
Padding="-10,0,0,0"
|
||||||
|
Command="{Binding ToggleFullscreen}"
|
||||||
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
|
||||||
InputGesture="F11" />
|
InputGesture="F11" />
|
||||||
<MenuItem>
|
<MenuItem
|
||||||
|
Padding="0"
|
||||||
|
Command="{Binding ToggleStartGamesInFullscreen}"
|
||||||
|
Header="{locale:Locale MenuBarOptionsStartGamesInFullscreen}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
<CheckBox
|
||||||
MinWidth="250">
|
MinWidth="{DynamicResource CheckBoxSize}"
|
||||||
<TextBlock Text="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"/>
|
MinHeight="{DynamicResource CheckBoxSize}"
|
||||||
</CheckBox>
|
IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
||||||
|
Padding="0" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
|
<MenuItem.Styles>
|
||||||
|
<Style Selector="Viewbox#PART_IconPresenter">
|
||||||
|
<Setter Property="MaxHeight" Value="36" />
|
||||||
|
<Setter Property="MinHeight" Value="36" />
|
||||||
|
<Setter Property="MaxWidth" Value="36" />
|
||||||
|
<Setter Property="MinWidth" Value="36" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||||
|
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||||
|
</Style>
|
||||||
|
</MenuItem.Styles>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem IsVisible="{Binding ShowConsoleVisible}">
|
<MenuItem
|
||||||
|
Padding="0"
|
||||||
|
IsVisible="{Binding ShowConsoleVisible}"
|
||||||
|
Command="{Binding ToggleShowConsole}"
|
||||||
|
Header="{locale:Locale MenuBarOptionsShowConsole}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
<CheckBox
|
||||||
MinWidth="250">
|
MinWidth="{DynamicResource CheckBoxSize}"
|
||||||
<TextBlock Text="{locale:Locale MenuBarOptionsShowConsole}"/>
|
MinHeight="{DynamicResource CheckBoxSize}"
|
||||||
</CheckBox>
|
IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
||||||
|
Padding="0" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
|
<MenuItem.Styles>
|
||||||
|
<Style Selector="Viewbox#PART_IconPresenter">
|
||||||
|
<Setter Property="MaxHeight" Value="36" />
|
||||||
|
<Setter Property="MinHeight" Value="36" />
|
||||||
|
<Setter Property="MaxWidth" Value="36" />
|
||||||
|
<Setter Property="MinWidth" Value="36" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||||
|
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||||
|
</Style>
|
||||||
|
</MenuItem.Styles>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Name="ChangeLanguageMenuItem" Header="{locale:Locale MenuBarOptionsChangeLanguage}" />
|
<MenuItem
|
||||||
<MenuItem Name="ToggleFileTypesMenuItem" Header="{locale:Locale MenuBarShowFileTypes}" />
|
Name="ChangeLanguageMenuItem"
|
||||||
|
Padding="-10,0,0,0"
|
||||||
|
Header="{locale:Locale MenuBarOptionsChangeLanguage}" />
|
||||||
|
<MenuItem
|
||||||
|
Name="ToggleFileTypesMenuItem"
|
||||||
|
Padding="-10,0,0,0"
|
||||||
|
Header="{locale:Locale MenuBarShowFileTypes}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Click="OpenSettings"
|
Click="OpenSettings"
|
||||||
|
Padding="-10,0,0,0"
|
||||||
Header="{locale:Locale MenuBarOptionsSettings}"
|
Header="{locale:Locale MenuBarOptionsSettings}"
|
||||||
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ManageProfiles}"
|
Command="{Binding ManageProfiles}"
|
||||||
|
Padding="-10,0,0,0"
|
||||||
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
|
||||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||||
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
|
||||||
@@ -113,7 +152,7 @@
|
|||||||
InputGesture="Escape"
|
InputGesture="Escape"
|
||||||
IsEnabled="{Binding IsGameRunning}"
|
IsEnabled="{Binding IsGameRunning}"
|
||||||
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
|
||||||
<MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
<MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Name="ScanAmiiboMenuItem"
|
Name="ScanAmiiboMenuItem"
|
||||||
@@ -122,12 +161,12 @@
|
|||||||
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
Header="{locale:Locale MenuBarActionsScanAmiibo}"
|
||||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding TakeScreenshot}"
|
Command="{Binding TakeScreenshot}"
|
||||||
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
|
||||||
InputGesture="{Binding ScreenshotKey}"
|
InputGesture="{Binding ScreenshotKey}"
|
||||||
IsEnabled="{Binding IsGameRunning}" />
|
IsEnabled="{Binding IsGameRunning}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding HideUi}"
|
Command="{Binding HideUi}"
|
||||||
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
Header="{locale:Locale MenuBarFileToolsHideUi}"
|
||||||
InputGesture="{Binding ShowUiKey}"
|
InputGesture="{Binding ShowUiKey}"
|
||||||
IsEnabled="{Binding IsGameRunning}" />
|
IsEnabled="{Binding IsGameRunning}" />
|
||||||
@@ -138,8 +177,8 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
|
||||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
|
||||||
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="{locale:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
<MenuItem Header="{locale:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||||
<MenuItem Header="{locale:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click"/>
|
<MenuItem Header="{locale:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click"/>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user