Compare commits

...

35 Commits

Author SHA1 Message Date
riperiperi
492a046335 Vulkan: Buffer Mirrors for MacOS performance (#4899)
* Initial implementation of buffer mirrors

Generally slower right now, goal is to reduce render passes in games that do inline updates

Fix support buffer mirrors

Reintroduce vertex buffer mirror

Add storage buffer support

Optimisation part 1

More optimisation

Avoid useless data copies.

Remove unused cbIndex stuff

Properly set write flag for storage buffers.

Fix minor issues

Not sure why this was here.

Fix BufferRangeList

Fix some big issues

Align storage buffers rather than getting full buffer as a range

Improves mirrorability of read-only storage buffers

Increase staging buffer size, as it now contains mirrors

Fix some issues with buffers not updating

Fix buffer SetDataUnchecked offset for one of the paths when using mirrors

Fix buffer mirrors interaction with buffer textures

Fix mirror rebinding

Move GetBuffer calls on indirect draws before BeginRenderPass to avoid draws without render pass

Fix mirrors rebase

Fix rebase 2023

* Fix crash when using stale vertex buffer

Similar to `Get` with a size that's too large, just treat it as a clamp.

* Explicitly set support buffer as mirrorable

* Address feedback

* Remove unused fragment of MVK workaround

* Replace logging for staging buffer OOM

* Address format issues

* Address more format issues

* Mini cleanup

* Address more things

* Rename BufferRangeList

* Support bounding range for ClearMirrors and UploadPendingData

* Add maximum size for vertex buffer mirrors

* Enable index buffer mirrors

Enabled on all platforms for the IbStreamer.

* Feedback

* Remove mystery BufferCache change

Probably macos related?

* Fix mirrors not creating when staging buffer is empty.

* Change log level to debug
2023-08-14 14:18:47 -03:00
gdkchan
550fd4a733 Simplify resolution scale updates (#5541) 2023-08-14 13:57:39 -03:00
riperiperi
33f544fd92 GPU: Track basic buffer copies that modify texture memory (#5554)
This branch changes the buffer copy fast path to notify memory tracking for all resources that aren't buffers. This fixes cases where games would copy buffer data directly into texture memory, which before would only work if the texture did not already exist. I imagine this happens when the guest driver is moving data between allocations or uploading it.

Since this only affects the fast path, cases where the source data has been modified from GPU (fast path copy destination doesn't count) will still fail to notify the texture, though I don't imagine games will do this. This should be resolved in future.

This should fix some texture issues with guest OpenGL games on switch, such as Dragon Quest Builders.

This may also be useful in future for games that move shader data around memory, if we end up using memory tracking for those.
2023-08-14 08:41:11 +02:00
gdkchan
b423197619 Delete ShaderConfig and organize shader resources/definitions better (#5509)
* Move some properties out of ShaderConfig

* Stop using ShaderConfig on backends

* Replace ShaderConfig usages on Translator and passes

* Move remaining properties out of ShaderConfig and delete ShaderConfig

* Remove ResourceManager property from TranslatorContext

* Move Rewriter passes to separate transform pass files

* Fix TransformPasses.RunPass on cases where a node is removed

* Move remaining ClipDistancePrimitivesWritten and UsedFeatures updates to decode stage

* Reduce excessive parameter passing a bit by using structs more

* Remove binding parameter from ShaderProperties methods since it is redundant

* Replace decoder instruction checks with switch statement

* Put GLSL on the same plan as SPIR-V for input/output declaration

* Stop mutating TranslatorContext state when Translate is called

* Pass most of the graphics state using a struct instead of individual query methods

* Auto-format

* Auto-format

* Add backend logging interface

* Auto-format

* Remove unnecessary use of interpolated strings

* Remove more modifications of AttributeUsage after decode

* PR feedback

* gl_Layer is not supported on compute
2023-08-13 22:26:42 -03:00
Marco Carvalho
8edfb2bc7b "static readonly" constants should be "const" instead (#5560)
* "static readonly" constants should be "const" instead

* change fields to PascalCase
2023-08-13 19:07:57 -03:00
MutantAura
ddefb4fff4 Remove animations on listbox items (#5563) 2023-08-13 22:40:40 +02:00
MutantAura
2efd74b9cb Ava UI: Make some settings methods async (#5332)
* Ava: Asynchronously load Vulkan device settings items.

* Sound checks, timezones and network interface async

* Refresh UI items once awaited tasks complete

* Remove unused dep

* Timezone UI update

* Use UIThread dispatcher for thread-unsafe collections + simplify GPU collection.

* Remove empty lines

* Remove unused string

* Dispatch property changes

* format changes

* format 2

* Use Tasks instead of async void

* Make NetworkInterfaceIndex access thread safe.
2023-08-12 22:43:03 +02:00
riperiperi
8c61ddd49d Ava UI: Allow DPI switching (#5558)
ForceDpiAware.Windows has a side effect of forcing the application DPI to be the same as the primary monitor. This isn't good if you have multiple monitors with different DPI.

On Avalonia, I don't think there are any downsides to disabling this. When it's disabled, `ForceDpiAware.GetWindowScaleFactor` always returns 1.
2023-08-12 13:02:22 -03:00
Isaac Marovitz
7b2225c6b0 Ava UI: Avalonia 11 & FluentAvalonia 2 Support (#4362)
* It builds

(Doesn’t run waiting on FluentAvalonia Preview 5 Release)

* Enable CompiledBindings by default

* Ignore `PointerPressedEventArgs` Init warning

* Define MIME and UTI Types

* Update `UserProfileImageSelectorView` to StorageProvider API

* PFS0 Magic

* Update `MainWindowViewModel` to StorageProvider API

* Update `SettingsUIView` to StorageProvider API

* Update `ApplicationHelper` to StorageProvider API

* Use `IsCheckChanged`

* Rename events

* Update Fluent Avalonia to Preivew 5

* More package updates

* Fix long selection bar

* return glyph value directly, instead of using a binding

* fix menu item checkboxes

* Fix build

* Update to Preview 6

Unicorn conflict

Fix remaining package oopsie

* Fix issues from merge

* Fix some warnings

* Warnings

* Squashed commit of the following:

commit 79d1c190db
Author: Mary <mary@mary.zone>
Date:   Sun Apr 16 11:38:07 2023 +0200

    chore: Update Silk.NET to 2.17.1 (#4686)

commit 2bc88467eb
Author: Ac_K <Acoustik666@gmail.com>
Date:   Sun Apr 16 09:37:31 2023 +0000

    Update README.md

commit baf8752e74
Author: Vincenzo Nizza <vincenzonizzaufficio@gmail.com>
Date:   Sun Apr 16 11:19:33 2023 +0200

    Ensure the updater doesn't delete hidden or system files (#4626)

    * Copy desktop.ini to update directory if it exists in HomeDir

    * EnumerateFilesToDelete() exclude files with "Hidden" and "System" attributes

commit d5e4378aea
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Sun Apr 16 09:02:06 2023 +0000

    nuget: bump DynamicData from 7.13.1 to 7.13.5 (#4654)

    Bumps [DynamicData](https://github.com/reactiveui/DynamicData) from 7.13.1 to 7.13.5.
    - [Release notes](https://github.com/reactiveui/DynamicData/releases)
    - [Changelog](https://github.com/reactivemarbles/DynamicData/blob/main/ReleaseNotes.md)
    - [Commits](https://github.com/reactiveui/DynamicData/compare/7.13.1...7.13.5)

    ---
    updated-dependencies:
    - dependency-name: DynamicData
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit 6dbcdfea47
Author: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
Date:   Sun Apr 16 09:09:02 2023 +0200

    Ava: Fix nca extraction window never closing & minor cleanup (#4569)

    * ava: Remove unused doWhileDeferred parameters

    * ava: Minimally improve swkbd dialog

    It's currently impossible to get the dialog to redirect focus to the InputBox.

    * ava: Fix nca extraction dialog never closing

    Also contains some minor cleanup

commit c5258cf082
Author: NitroTears <73270647+NitroTears@users.noreply.github.com>
Date:   Sun Apr 16 11:03:35 2023 +1000

    Ability to hide file types in Game List (#4555)

    * Added HiddenFileTypes to config state, and check to file enumeration

    * Added hiddenfiletypes checkboxes to the UI

    * Added Ava version of HiddenFileTypes

    * Inverted Hide to Show with file types, minor formatting

    * all variables with a reference to 'hidden' is now 'shown'

    * one more variable name changed

    * review feedback

    * added FileTypes extension methof to get the correlating config value

    * moved extension method to new folder and file in Ryujinx.Ui.Common

    * added default case for ToggleFileType

    * changed exception type to OutOfRangeException

commit 5c89e22bb9
Author: Daniel Shala <daniel.shala08@gmail.com>
Date:   Sat Apr 15 18:11:24 2023 +0200

    Added check for eventual symlink when displaying game files. (#4526)

    * Added check for eventual symlink when displaying game files.

    * Moved symlink check logic

    * Moved symlink check logic

    * Fixed prev commit

    ---------

    Co-authored-by: Daniel Shala <danielshala00@gmail.com>

commit 11ecff2ff0
Author: Alex Barney <thealexbarney@gmail.com>
Date:   Fri Apr 14 16:00:34 2023 -0700

    Rename Hipc to Cmif where appropriate (#3880)

commit 4c3f09644a
Author: MutantAura <44103205+MutantAura@users.noreply.github.com>
Date:   Wed Apr 12 20:18:40 2023 +0100

    Move swkbd message null check into constructor (#4671)

commit e187a8870a
Author: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
Date:   Wed Apr 12 03:09:47 2023 +0200

    HLE: Deal with empty title names properly (#4643)

    * hle: Deal with empty titleNames in some languages

    * gui: Fix displaying the wrong title name

    * Remove unnecessary bounds check

    * Fix a NRE when getting the version string

    * Restore empty string logic

commit a64fee29dc
Author: riperiperi <rhy3756547@hotmail.com>
Date:   Tue Apr 11 08:23:41 2023 +0100

    Vulkan: add situational "Fast Flush" mode (#4667)

    * Flush in the middle of long command buffers.

    * Vulkan: add situational "Fast Flush" mode

    The AutoFlushCounter class was added to periodically flush Vulkan command buffers throughout a frame, which reduces latency to the GPU as commands are submitted and processed much sooner. This was done by allowing command buffers to flush when framebuffer attachments changed.

    However, some games have incredibly long render passes with a large number of draws, and really aggressive data access that forces GPU sync.

    The Vulkan backend could potentially end up building a single command buffer for 4-5ms if a pass has enough draws, such as in BOTW. In the scenario where sync is waited on immediately after submission, this would have to wait for the completion of a much longer command buffer than usual.

    The solution is to force command buffer submission periodically in a "fast flush" mode. This will end up splitting render passes, but it will only enable if sync is aggressive enough.

    This should improve performance in GPU limited scenarios, or in games that aggressively wait on synchronization. In some games, it may only kick in when res scaling. It won't trigger in games like SMO where sync is not an issue.

    Improves performance in Pokemon Scarlet/Violet (res scaled) and BOTW (in general).

    * Add conversions in milliseconds next to flush timers.

commit 9ef94c8292
Author: riperiperi <rhy3756547@hotmail.com>
Date:   Tue Apr 11 07:55:04 2023 +0100

    ARMeilleure: Move TPIDR_EL0 and TPIDRRO_EL0 to NativeContext (#4661)

    * ARMeilleure: Move TPIDR_EL0 and TPIDRRO_EL0 to NativeContext

    Some games access these system registers several tens of thousands of times in a second from many different threads. While this isn't really crippling, it is a lot of wasted time spent in a reverse pinvoke transition.

    Example games are Pokemon Scarlet/Violet and BOTW. These games have a lot of different potential bottlenecks so it's unlikely you will see a consistent improvement, but it definitely disappears from the cpu profile.

    * Remove unreachable code.

    * Add ulong conversion for offsets

    * Nit

commit 915d6d044c
Author: riperiperi <rhy3756547@hotmail.com>
Date:   Tue Apr 11 07:32:31 2023 +0100

    OpenGL: Fix OBS/Overlays again by binding FB before present (#4668)

    This seems to have been removed by the Post-Processing PR, but it is required for the display in OBS to be the right way up and properly scaled.

    I've tested this with AA and FSR on MK8D and it seems to behave properly. Testing is welcome.

commit a4780ab33b
Author: MutantAura <44103205+MutantAura@users.noreply.github.com>
Date:   Mon Apr 10 23:04:31 2023 +0100

    Force activate parent window before dialog is shown (#4663)

* Fix build

Extraction dialogue not working

* Avalonia Preview 7

Needs Fluent Avalonia update still…

* Fix Render Scaling

* Update Fluent Avalonia

* Remove `pfs0` as runnable file type

* Restore Info.plist formatting

* Plist Format

* Update Avalonia.Svg.Skia

* Update theme code (TODO)

* swtich to using theme variants  for light dark

* Fix crashes

* Text centering issues

* Update `TitleUpdateViewModel` to StorageProvider API

* Fixed for new PR

(Will crash on launch)

* Fixes…

* UI: Fix sections extraction (#4820)

* UI: Fix sections extraction

There is currently an issue when the update NCA doesn't contains the section we want to extract, this is fixed by adding a check.
I have fixed the inverted handler of ExeFs/Logo introduced in #4755.

Fixes #4521

* Addresses feedback

* Fix issues…

* Preview 8

* Fix fuck ups

* Fixes

* More cleanup

* Ava 11 RC

Maybe there is a god

* Update FluentAvalonia

* update svg

* Second RC (kill me)

* It builds

* Ava 11

* Remove unnecessary usings

* Fix build

* Formatting

* GAS GAS GAS!!!!

* Fix DLC Window Crash

* Linux runner try not to crash challenge (impossible)

* Add app.manifest

* Fix accidental Silk.NET.Vulkan bump

* Try fix truncation

* Linux fix popup Windows

* Fix cutoff text on windows

* Status bar styling fixes

* Volume Toggle Split Button Fixes

* Fix load bar color

* Fix shortcuts

* Best we're gonna get

* Fix spacing

Co-authored-by: Exhigh <exhigh01@gmail.com>

* Formatting

* Fix Profile Dropdown

* Fix Window Startup Position

* Format Fixes

* Fix stupid mistake

* Fix accidental change

* Scaling Handler (peri pls make sure is working)

* Remove Locale Reflection Binding Use + Unsued Usings

* Fix formatting

Code styling

Ughhhh

Fix interface

Make TimeZoneConverter internal

* Remove bell workaround (no longer needed)

* Disable accent menu

* Update to Ava 11.0.2

* Peri suggestions

* Formatting

* Cleanup a bunch of jank

* Dependency update

* Berry fixes and suggestions

* Final suggestions

* Rename assemblyIdentity to Ryujinx.Emulator.Avalonia

---------

Co-authored-by: Emmanuel Hansen <emmausssss@gmail.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
Co-authored-by: Exhigh <exhigh01@gmail.com>
Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
2023-08-12 02:47:22 +02:00
TSRBerry
fe15c77d30 [Hotfix] hid: Prevent out of bounds array access (#5547)
* hid: Prevent out of bounds array access

* Cast player to uint

* Replace lambda function with local function
2023-08-10 00:29:15 -03:00
TSRBerry
5e9678c8fa Allow access to code memory for exefs mods (#5518)
* Allow access to code memory for exefs mods

* Add ASLR workaround for Skyline

* Hardcode allowCodeMemoryForJit to true
2023-08-09 18:27:45 -03:00
jcm
773e239db7 Implement color space passthrough option (#5531)
Co-authored-by: jcm <butt@butts.com>
2023-08-07 18:54:05 +01:00
gdkchan
42750a74f8 Do not add more code after alpha test discard on fragment shader (#5529)
* Do not add more code after alpha test discard on fragment shader

* Shader cache version bump
2023-08-07 12:20:37 -03:00
TSRBerry
3ab0a71c7b Fix PR build concurrency and stop auto assigning reviewers for draft PRs (#5519)
* build: Remove concurrency

It's called by checks anyway.

* Only assign reviewers for PRs that are ready for reviews
2023-08-06 23:25:02 +02:00
riperiperi
6e784e0aca GPU: Don't sync/bind index buffer when it's not in use (#5526)
* GPU: Don't sync/bind index buffer when it's not in use

Sometimes draws don't use an index buffer. It's not necessary to check or upload data for the current index buffer binding as it won't be used.

This fixes Pokemon: Legends Arceus updating a stale index buffer for every draw during its TFB pass, which was all non-indexed draws.

This probably didn't cost much on normal PCs, but it had a large impact on MacOS, which the macos1 release build avoided by mirroring index buffers (the PR currently does not). Needs buffer mirrors still for the rest of the performance.

There are additional cases where index buffers are bound or checked with non-indexed draws on the backend, but this one was straightforward to fix and has the largest impact. Testing is welcome to ensure nothing weird broke.

* Fix case with _rebind
2023-08-06 16:29:20 -03:00
sunshineinabox
5a0aa074b6 Enable VK_EXT_4444_formats (#5525) 2023-08-03 17:46:23 -03:00
dependabot[bot]
93aa40f1fb nuget: bump DiscordRichPresence from 1.1.3.18 to 1.2.1.24 (#5515)
Bumps [DiscordRichPresence](https://github.com/Lachee/discord-rpc-csharp) from 1.1.3.18 to 1.2.1.24.
- [Release notes](https://github.com/Lachee/discord-rpc-csharp/releases)
- [Commits](https://github.com/Lachee/discord-rpc-csharp/commits)

---
updated-dependencies:
- dependency-name: DiscordRichPresence
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:19:38 +02:00
TSRBerry
bedee64af5 Add slightly better workaround for current workflow issues (#5507)
* checks: Add retry logic to dotnet format style step as well

I can't imagine dotnet format whitespace ever segfaulting,
so hopefully it won't be needed there.

* checks: Replace bash scripts with unstable-commands action

* build: Add unstable-commands action for test step
2023-08-01 00:15:37 +02:00
Domenico V
86931cc3f1 (Graphics.Shader): Handle EmitSuatom constant dests and EmitSuld zero dest reg. (#5504)
* (Graphics.Shader): Handle EmitSuatom constant dests.

* Proper fix for EmitSuatom; fix EmitSuld.
2023-07-30 22:31:57 -03:00
Domenico V
2be8b6ea45 CPU (A64): Add Fmaxp & Fminp Scalar Inst.s, Fast & Slow Paths; with Tests. (#5502)
* Add Fmaxp & Fminp Scalar Inst.s, Fast & Slow Paths; with Tests.

* Ptc.InternalVersion = 5502
2023-07-30 20:57:37 -03:00
gdkchan
f95b7c5877 Fix incorrect fragment origin when YNegate is enabled (#4673)
* Fix incorrect fragment origin when YNegate is enabled

* Shader cache version bump

* Do not update support buffer if shader does not read gl_FragCoord

* Pass unscaled viewport size to the support buffer
2023-07-29 18:47:03 -03:00
TSRBerry
eb528ae0f0 Add workflow to automatically check code style issues for PRs (#4670)
* Add workflow to perform automated checks for PRs

* Downgrade Microsoft.CodeAnalysis to 4.4.0

This is a workaround to fix issues with dotnet-format.
See:
- https://github.com/dotnet/format/issues/1805
- https://github.com/dotnet/format/issues/1800

* Adjust editorconfig to be more compatible with Ryujinx code-style

* Adjust .editorconfig line endings to match .gitattributes

* Disable 'prefer switch expression' rule

* Remove naming styles

These are the default rules, so we don't need to override them.

* Silence IDE0060 in .editorconfig

* Slightly adjust .editorconfig

* Add lost workflow changes

* Move .editorconfig comment to the top

* .editorconfig: private static readonly fields should be _lowerCamelCase

* .editorconfig: Remove alignment for declarations as well

* editorconfig: Add rule for local constants

* Disable CA1822 for HLE services

* Disable CA1822 for ViewModels

Bindings won't work with static members, but this issue is silently ignored.

* Run dotnet format for the whole solution

* Check result code of SDL_GetDisplayBounds

* Fix dotnet format style issues

* Add missing trailing commas

* Update Microsoft.CodeAnalysis.CSharp to 4.6.0

Skipping 4.5.0 since it breaks dotnet format

* Restore old default naming rules for dotnet format

* Add naming rule exception for CPU tests

* checks: Include all files before excluding paths

* Fix dotnet format issues

* Check dotnet format version

* checks: Run dotnet format with severity info again

* checks: Disable naming style rules until they won't crash the process anymore

* Remove unread private member

* checks: Attempt to run analyzers 3 times before giving up

* checks: Enable naming style rules again with the new retry logic
2023-07-24 18:35:04 +02:00
Mary
487261592e ava: Fix regression on title updater and dlc manager window caused by precious commit 2023-07-21 22:50:10 +02:00
MutantAura
9e04e6cba1 Ava UI: Remove IsActive checks from dialog methods (#5456)
* Remove `IsActive` checks from dialog methods

* Remove old windows bandaid

* Remove null dialog code path entirely and return nothing.
2023-07-21 12:24:13 +01:00
TSRBerry
4cf2419e6c HLE: Fix corrupted Mii structs (#5468)
* StructArrayHelpers: Add PureAttribute to all AsSpan() methods

* Fix broken Mii structs
2023-07-19 22:02:31 -03:00
Mary
440abac9f8 chore: Update Ryujinx.SDL2-CS to 2.28.1 (#5453) 2023-07-18 16:08:48 +02:00
TSRBerry
732714349e [Hotfix] sockets: Resolve empty port requests to 0 again (#5459) 2023-07-17 20:47:47 +02:00
TSRBerry
016262514d cpu: Hotfix missing ToNearest rounding mode cases 2023-07-16 20:39:08 +01:00
TSRBerry
326749498b [Ryujinx.HLE] Address dotnet-format issues (#5380)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
2023-07-16 19:31:14 +02:00
Mary
fec8291c17 infra: do not assign developers team for now
Hopefully fix PR triage for real...
2023-07-14 11:32:14 +02:00
gdkchan
c5d9e67cb2 Fix some Vulkan validation errors (#5452)
* Fix some validation errors and silence the annoying pipeline barrier error

* Remove bogus decref/incref on index buffer state

* Make unsafe blit opt-in rather than opt-out

* Remove Vulkan debugger messages blacklist

* Adjust GetImageUsage to not set the storage bit for multisample textures if not supported
2023-07-14 09:08:52 +02:00
Mary
e5261228d7 infra: Fix team name in reviewer.yml 2023-07-12 19:22:09 +02:00
Mary
e61c09bc85 infra: Fix PR triage once and for all (#5442)
Switch to a custom made python script that query GitHub API to grab latest state of the PR after label assign.
2023-07-12 18:31:08 +02:00
ealekseychik
ac2444f908 Move ShaderBinaries into individual .spv files (#5280)
* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Update .csproj file

* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Split shader binaries into folders, use string.Join to create filepath

* Move files back to general binaries folder

* Remove ShaderSource suffix from file names

---------

Co-authored-by: Egor Alekseychik <e.alekseychik@syberry.com>
Co-authored-by: Gabriel A <gab.dark.100@gmail.com>
2023-07-11 14:41:18 -03:00
gdkchan
9c6071a645 Move support buffer update out of the backends (#5411)
* Move support buffer update out of the backends

* Fix render scale init and remove redundant state from SupportBufferUpdater

* Stop passing texture scale to the backends

* XML docs for SupportBufferUpdater
2023-07-11 14:07:41 -03:00
1367 changed files with 14865 additions and 14788 deletions

View File

@@ -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

View File

@@ -1,8 +0,0 @@
addReviewers: true
reviewers:
- marysaka
filterLabels:
include:
- audio

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
filterLabels:
include:
- cpu

View File

@@ -1,4 +0,0 @@
addReviewers: true
reviewers:
- Ryujinx/developers

View File

@@ -1,10 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
filterLabels:
include:
- gpu

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- Ack77
- emmauss
- TSRBerry
- marysaka
filterLabels:
include:
- gui

View File

@@ -1,11 +0,0 @@
addReviewers: true
reviewers:
- gdkchan
- Ack77
- marysaka
- TSRBerry
filterLabels:
include:
- horizon

View File

@@ -1,9 +0,0 @@
addReviewers: true
reviewers:
- marysaka
- TSRBerry
filterLabels:
include:
- infra

32
.github/reviewers.yml vendored Normal file
View 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
View 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))

View File

@@ -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
View 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

View File

@@ -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'

View File

@@ -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'

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)
{ {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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";

View File

@@ -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
{ {

View File

@@ -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*/)]

View File

@@ -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();

View File

@@ -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);

View File

@@ -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,
}; };
} }

View File

@@ -8,6 +8,6 @@
Alsa = 3, Alsa = 3,
CoreAudio = 4, CoreAudio = 4,
Wasapi = 5, Wasapi = 5,
Dummy = 6 Dummy = 6,
} }
} }

View File

@@ -3,6 +3,6 @@
public enum SoundIoDeviceAim public enum SoundIoDeviceAim
{ {
SoundIoDeviceAimInput = 0, SoundIoDeviceAimInput = 0,
SoundIoDeviceAimOutput = 1 SoundIoDeviceAimOutput = 1,
} }
} }

View File

@@ -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>

View File

@@ -3,7 +3,6 @@ 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.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
@@ -24,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()
@@ -89,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";
@@ -98,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)
{ {
@@ -133,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)
{ {

View File

@@ -3,6 +3,7 @@ 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;
@@ -54,6 +55,7 @@ using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing; 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 ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
@@ -167,9 +169,9 @@ namespace Ryujinx.Ava
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())
{ {
@@ -186,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;
@@ -193,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 &&
@@ -210,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;
} }
@@ -229,6 +229,11 @@ namespace Ryujinx.Ava
_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(() =>
@@ -259,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));
} }
@@ -353,7 +358,7 @@ namespace Ryujinx.Ava
_viewModel.SetUiProgressHandlers(Device); _viewModel.SetUiProgressHandlers(Device);
RendererHost.SizeChanged += Window_SizeChanged; RendererHost.BoundsChanged += Window_BoundsChanged;
_isActive = true; _isActive = true;
@@ -461,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();
@@ -842,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;
@@ -887,11 +893,12 @@ namespace Ryujinx.Ava
_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();

View File

@@ -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?",

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 &gt; Image"> <Style Selector="#TitleBarHost &gt; Image">
<Setter Property="Margin" Value="10" /> <Setter Property="Margin"
Value="10" />
</Style> </Style>
<Style Selector="#TitleBarHost &gt; Label"> <Style Selector="#TitleBarHost &gt; 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>

View 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>

View File

@@ -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;
@@ -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);
@@ -300,7 +304,6 @@ namespace Ryujinx.Ava.Common
}; };
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)
{ {

View File

@@ -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 { }

View File

@@ -37,7 +37,7 @@ namespace Ryujinx.Modules
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;
@@ -344,22 +344,22 @@ namespace Ryujinx.Modules
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile) private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
{ {
// Multi-Threaded Updater // Multi-Threaded Updater
long chunkSize = _buildSize / _connectionCount; long chunkSize = _buildSize / ConnectionCount;
long remainderChunk = _buildSize % _connectionCount; long remainderChunk = _buildSize % ConnectionCount;
int completedRequests = 0; int completedRequests = 0;
int totalProgressPercentage = 0; int totalProgressPercentage = 0;
int[] progressPercentage = new int[_connectionCount]; int[] progressPercentage = new int[ConnectionCount];
List<byte[]> list = new(_connectionCount); List<byte[]> list = new(ConnectionCount);
List<WebClient> webClients = new(_connectionCount); List<WebClient> webClients = new(ConnectionCount);
for (int i = 0; i < _connectionCount; i++) for (int i = 0; i < ConnectionCount; i++)
{ {
list.Add(Array.Empty<byte>()); list.Add(Array.Empty<byte>());
} }
for (int i = 0; i < _connectionCount; i++) for (int i = 0; i < ConnectionCount; i++)
{ {
#pragma warning disable SYSLIB0014 #pragma warning disable SYSLIB0014
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient. // TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
@@ -368,7 +368,7 @@ namespace Ryujinx.Modules
webClients.Add(client); webClients.Add(client);
if (i == _connectionCount - 1) if (i == ConnectionCount - 1)
{ {
client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}"); client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}");
} }
@@ -385,7 +385,7 @@ namespace Ryujinx.Modules
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage); Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage); Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
taskDialog.SetProgressBarState(totalProgressPercentage / _connectionCount, TaskDialogProgressState.Normal); taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
}; };
client.DownloadDataCompleted += (_, args) => client.DownloadDataCompleted += (_, args) =>
@@ -404,10 +404,10 @@ namespace Ryujinx.Modules
list[index] = args.Result; list[index] = args.Result;
Interlocked.Increment(ref completedRequests); Interlocked.Increment(ref completedRequests);
if (Equals(completedRequests, _connectionCount)) if (Equals(completedRequests, ConnectionCount))
{ {
byte[] mergedFileBytes = new byte[_buildSize]; byte[] mergedFileBytes = new byte[_buildSize];
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < _connectionCount; connectionIndex++) for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
{ {
Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length); Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length);
destinationOffset += list[connectionIndex].Length; destinationOffset += list[connectionIndex].Length;

View File

@@ -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.

View File

@@ -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>

View File

@@ -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,

View File

@@ -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"

View File

@@ -4,9 +4,6 @@ using Avalonia.Threading;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using System.Threading.Tasks; using System.Threading.Tasks;
#if DEBUG
using Avalonia;
#endif
namespace Ryujinx.Ava.UI.Applet namespace Ryujinx.Ava.UI.Applet
{ {
@@ -21,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)
@@ -44,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; }

View File

@@ -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" />

View File

@@ -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}" />

View File

@@ -299,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);
} }
} }
@@ -309,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);
} }
} }
@@ -319,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);
} }
} }

View File

@@ -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"

View File

@@ -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)
{ {

View File

@@ -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"

View File

@@ -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)
{ {

View File

@@ -315,8 +315,10 @@ namespace Ryujinx.Ava.UI.Helpers
Window parent = GetMainWindow(); Window parent = GetMainWindow();
if (parent is { IsActive: true } and MainWindow window && window.ViewModel.IsGameRunning) if (parent is MainWindow window)
{ {
parent.Activate();
contentDialogOverlayWindow = new() contentDialogOverlayWindow = new()
{ {
Height = parent.Bounds.Height, Height = parent.Bounds.Height,
@@ -369,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;
@@ -390,7 +394,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
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;
} }

View File

@@ -4,6 +4,6 @@
{ {
List, List,
Grid, Grid,
Chip Chip,
} }
} }

View File

@@ -1,6 +1,4 @@
using Avalonia.Data;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -38,13 +36,7 @@ namespace Ryujinx.Ava.UI.Helpers
public override object ProvideValue(IServiceProvider serviceProvider) public override object ProvideValue(IServiceProvider serviceProvider)
{ {
ReflectionBindingExtension binding = new($"[{_key}]") return this[_key];
{
Mode = BindingMode.OneWay,
Source = this,
};
return binding.ProvideValue(serviceProvider);
} }
} }
} }

View File

@@ -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();
}
}
}
}

View File

@@ -42,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));

View File

@@ -31,7 +31,6 @@ namespace Ryujinx.Ava.UI.Helpers
OnTextInput(new TextInputEventArgs OnTextInput(new TextInputEventArgs
{ {
Text = text, Text = text,
Device = KeyboardDevice.Instance,
Source = this, Source = this,
RoutedEvent = TextInputEvent, RoutedEvent = TextInputEvent,
}); });

View 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();
}
}
}

View File

@@ -2,6 +2,7 @@ using LibHac.Fs;
using LibHac.Ncm; using LibHac.Ncm;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.App.Common; using Ryujinx.Ui.App.Common;
using System; using System;
using System.IO; using System.IO;
@@ -81,7 +82,7 @@ namespace Ryujinx.Ava.UI.Models
Task.Run(() => Task.Run(() =>
{ {
var saveRoot = Path.Combine(MainWindow.MainWindowViewModel.VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}"); var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
long totalSize = GetDirectorySize(saveRoot); long totalSize = GetDirectorySize(saveRoot);

View File

@@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Media; using Avalonia.Media;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
@@ -88,7 +87,8 @@ namespace Ryujinx.Ava.UI.Models
private void UpdateBackground() private void UpdateBackground()
{ {
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)
{ {

View File

@@ -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);
} }
@@ -149,9 +149,10 @@ namespace Ryujinx.Ava.UI.Renderer
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:
@@ -164,7 +165,7 @@ namespace Ryujinx.Ava.UI.Renderer
var evnt = new PointerPressedEventArgs( var evnt = new PointerPressedEventArgs(
this, this,
pointer, pointer,
VisualRoot, this,
rootVisualPosition, rootVisualPosition,
(ulong)Environment.TickCount64, (ulong)Environment.TickCount64,
properties, properties,
@@ -184,7 +185,7 @@ namespace Ryujinx.Ava.UI.Renderer
var evnt = new PointerReleasedEventArgs( var evnt = new PointerReleasedEventArgs(
this, this,
pointer, pointer,
VisualRoot, this,
rootVisualPosition, rootVisualPosition,
(ulong)Environment.TickCount64, (ulong)Environment.TickCount64,
properties, properties,
@@ -201,7 +202,7 @@ namespace Ryujinx.Ava.UI.Renderer
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),
@@ -212,6 +213,7 @@ namespace Ryujinx.Ava.UI.Renderer
break; break;
} }
} }
#pragma warning restore CS0618
} }
} }

View File

@@ -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)

View File

@@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
@@ -88,21 +87,19 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
Version = Program.Version; Version = Program.Version;
var assets = AvaloniaLocator.Current.GetService<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);

View File

@@ -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;
@@ -90,12 +90,19 @@ namespace Ryujinx.Ava.UI.ViewModels
get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
} }
public IStorageProvider StorageProvider;
public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
_virtualFileSystem = virtualFileSystem; _virtualFileSystem = virtualFileSystem;
_titleId = titleId; _titleId = titleId;
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
@@ -195,29 +202,24 @@ 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.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 (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);
}
}
} }
} }

View File

@@ -3,6 +3,7 @@ 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;
@@ -105,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; }
@@ -131,6 +130,7 @@ 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,
@@ -144,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;
@@ -891,6 +892,7 @@ 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; }
@@ -1188,7 +1190,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
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)
{ {
@@ -1259,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;
@@ -1271,43 +1285,57 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void InstallFirmwareFromFile() public async void InstallFirmwareFromFile()
{ {
if (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 (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");
@@ -1349,25 +1377,6 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public void ToggleFileType(string fileType)
{
_ = fileType switch
{
#pragma warning disable IDE0055 // Disable formatting
"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),
#pragma warning restore IDE0055
};
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);
@@ -1378,78 +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 (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
OpenFileDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
}; AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
dialog.Filters.Add(new FileDialogFilter
{ {
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats], new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
Extensions =
{ {
"nsp", Patterns = new[] { "*.nsp", "*.xci", "*.nca", "*.nro", "*.nso" },
"pfs0", AppleUniformTypeIdentifiers = new[]
"xci", {
"nca", "com.ryujinx.nsp",
"nro", "com.ryujinx.xci",
"nso", "com.ryujinx.nca",
"com.ryujinx.nro",
"com.ryujinx.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" }
},
}
}); });
#pragma warning disable IDE0055 // Disable formatting if (result.Count > 0)
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
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" } });
#pragma warning restore IDE0055
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 (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
OpenFolderDialog dialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle], Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
}; AllowMultiple = false
});
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);
}
} }
} }

View File

@@ -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;
@@ -24,6 +23,7 @@ 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
@@ -44,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;
@@ -145,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; }
@@ -277,7 +278,7 @@ namespace Ryujinx.Ava.UI.ViewModels
_contentManager = contentManager; _contentManager = contentManager;
if (Program.PreviewerDetached) if (Program.PreviewerDetached)
{ {
LoadTimeZones(); Task.Run(LoadTimeZones);
} }
} }
@@ -289,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)
@@ -320,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();
@@ -343,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)
@@ -415,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));
@@ -435,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;
@@ -448,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()
@@ -506,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);

View File

@@ -1,7 +1,7 @@
using Avalonia; 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;
@@ -70,12 +70,19 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public IStorageProvider StorageProvider;
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId)
{ {
VirtualFileSystem = virtualFileSystem; VirtualFileSystem = virtualFileSystem;
TitleId = titleId; TitleId = titleId;
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
StorageProvider = desktop.MainWindow.StorageProvider;
}
TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
try try
@@ -202,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 (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();

View File

@@ -105,7 +105,7 @@ 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))
{ {

View File

@@ -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>

View File

@@ -31,8 +31,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
if (visual is ToggleButton button && visual is not 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;

View File

@@ -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">

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -30,8 +30,8 @@ namespace Ryujinx.Ava.UI.Views.Main
{ {
InitializeComponent(); InitializeComponent();
ToggleFileTypesMenuItem.Items = GenerateToggleFileTypeItems(); ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
ChangeLanguageMenuItem.Items = GenerateLanguageMenuItems(); ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
} }
private CheckBox[] GenerateToggleFileTypeItems() private CheckBox[] GenerateToggleFileTypeItems()
@@ -45,7 +45,7 @@ namespace Ryujinx.Ava.UI.Views.Main
{ {
Content = $".{fileName}", Content = $".{fileName}",
IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes), IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes),
Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName)), Command = MiniCommand.Create(() => Window.ToggleFileType(fileName)),
}); });
} }

View File

@@ -8,7 +8,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView" x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView"
x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel"> x:DataType="viewModels:MainWindowViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:MainWindowViewModel /> <viewModels:MainWindowViewModel />
@@ -46,7 +45,7 @@
Margin="0,0,5,0" Margin="0,0,5,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Background="Transparent" Background="Transparent"
Command="{ReflectionBinding LoadApplications}"> Click="Refresh_OnClick">
<ui:SymbolIcon <ui:SymbolIcon
Width="50" Width="50"
Height="100" Height="100"
@@ -64,7 +63,7 @@
Grid.Column="2" Grid.Column="2"
Height="6" Height="6"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource HighlightColor}" Foreground="{DynamicResource SystemAccentColorLight2}"
IsVisible="{Binding StatusBarVisible}" IsVisible="{Binding StatusBarVisible}"
Maximum="{Binding StatusBarProgressMaximum}" Maximum="{Binding StatusBarProgressMaximum}"
Value="{Binding StatusBarProgressValue}" /> Value="{Binding StatusBarProgressValue}" />
@@ -93,6 +92,7 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
@@ -109,6 +109,7 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
@@ -125,20 +126,32 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<ui:ToggleSplitButton <ToggleSplitButton
Name="VolumeStatus" Name="VolumeStatus"
Padding="5,0,5,0" Padding="5,0,5,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Background="{DynamicResource ThemeContentBackgroundColor}"
BorderThickness="0"
Content="{Binding VolumeStatusText}" Content="{Binding VolumeStatusText}"
IsChecked="{Binding VolumeMuted}" IsChecked="{Binding VolumeMuted}"
IsVisible="{Binding !ShowLoadProgress}"> IsVisible="{Binding !ShowLoadProgress}"
<ui:ToggleSplitButton.Flyout> Background="Transparent"
BorderThickness="0"
CornerRadius="0">
<ToggleSplitButton.Styles>
<Style Selector=":checked">
<Style Selector="^:checked ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
</Style>
</Style>
<Style Selector="Border#SeparatorBorder">
<Setter Property="Opacity" Value="0" />
</Style>
</ToggleSplitButton.Styles>
<ToggleSplitButton.Flyout>
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway"> <Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
<Grid Margin="0"> <Grid Margin="0">
<Slider <Slider
@@ -156,13 +169,14 @@
Value="{Binding Volume}" /> Value="{Binding Volume}" />
</Grid> </Grid>
</Flyout> </Flyout>
</ui:ToggleSplitButton.Flyout> </ToggleSplitButton.Flyout>
</ui:ToggleSplitButton> </ToggleSplitButton>
<Border <Border
Width="2" Width="2"
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
@@ -177,6 +191,7 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
@@ -191,6 +206,7 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
@@ -205,6 +221,7 @@
Height="12" Height="12"
Margin="0" Margin="0"
BorderBrush="Gray" BorderBrush="Gray"
Background="Gray"
BorderThickness="1" BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" /> IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock

View File

@@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -48,5 +49,10 @@ namespace Ryujinx.Ava.UI.Views.Main
ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
} }
private void Refresh_OnClick(object sender, RoutedEventArgs e)
{
Window.LoadApplications();
}
} }
} }

View File

@@ -9,7 +9,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls" x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls"
x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel"> x:DataType="viewModels:MainWindowViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:MainWindowViewModel /> <viewModels:MainWindowViewModel />
@@ -23,7 +22,7 @@
MinWidth="40" MinWidth="40"
Margin="5,2,0,2" Margin="5,2,0,2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Command="{ReflectionBinding SetListMode}" Command="{Binding SetListMode}"
IsEnabled="{Binding IsGrid}"> IsEnabled="{Binding IsGrid}">
<ui:FontIcon <ui:FontIcon
Margin="0" Margin="0"
@@ -37,7 +36,7 @@
MinWidth="40" MinWidth="40"
Margin="5,2,5,2" Margin="5,2,5,2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Command="{ReflectionBinding SetGridMode}" Command="{Binding SetGridMode}"
IsEnabled="{Binding IsList}"> IsEnabled="{Binding IsList}">
<ui:FontIcon <ui:FontIcon
Margin="0" Margin="0"
@@ -79,13 +78,13 @@
KeyUp="SearchBox_OnKeyUp" KeyUp="SearchBox_OnKeyUp"
Text="{Binding SearchText}" Text="{Binding SearchText}"
Watermark="{locale:Locale MenuSearch}" /> Watermark="{locale:Locale MenuSearch}" />
<ui:DropDownButton <DropDownButton
Width="150" Width="150"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center" VerticalAlignment="Center"
Content="{Binding SortName}" Content="{Binding SortName}"
DockPanel.Dock="Right"> DockPanel.Dock="Right">
<ui:DropDownButton.Flyout> <DropDownButton.Flyout>
<Flyout Placement="Bottom"> <Flyout Placement="Bottom">
<StackPanel <StackPanel
Margin="0" Margin="0"
@@ -164,8 +163,8 @@
Tag="Descending" /> Tag="Descending" />
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</ui:DropDownButton.Flyout> </DropDownButton.Flyout>
</ui:DropDownButton> </DropDownButton>
<TextBlock <TextBlock
Margin="10,0" Margin="10,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"

View File

@@ -8,7 +8,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />

View File

@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />

View File

@@ -9,7 +9,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
Design.Width="1000" Design.Width="1000"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
@@ -54,7 +53,7 @@
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}" ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
SelectedIndex="{Binding PreferredGpuIndex}" SelectedIndex="{Binding PreferredGpuIndex}"
Items="{Binding AvailableGpus}"/> ItemsSource="{Binding AvailableGpus}"/>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<Separator Height="1" /> <Separator Height="1" />
@@ -73,6 +72,10 @@
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}"> ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" /> <TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
</CheckBox>
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" <TextBlock VerticalAlignment="Center"

View File

@@ -8,7 +8,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel" x:DataType="viewModels:SettingsViewModel"
Focusable="True"> Focusable="True">
<Design.DataContext> <Design.DataContext>

View File

@@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
_currentAssigner = new ButtonKeyAssigner(button); _currentAssigner = new ButtonKeyAssigner(button);
FocusManager.Instance?.Focus(this, NavigationMethod.Pointer); this.Focus(NavigationMethod.Pointer);
PointerPressed += MouseClick; PointerPressed += MouseClick;

View File

@@ -8,7 +8,6 @@
xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input" xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />

View File

@@ -8,7 +8,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />

View File

@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
@@ -37,7 +36,7 @@
<ComboBox SelectedIndex="{Binding NetworkInterfaceIndex}" <ComboBox SelectedIndex="{Binding NetworkInterfaceIndex}"
ToolTip.Tip="{locale:Locale NetworkInterfaceTooltip}" ToolTip.Tip="{locale:Locale NetworkInterfaceTooltip}"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
Items="{Binding NetworkInterfaceList}" ItemsSource="{Binding NetworkInterfaceList}"
Width="250" /> Width="250" />
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>

View File

@@ -3,12 +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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:CompileBindings="True" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
x:DataType="viewModels:SettingsViewModel" mc:Ignorable="d"
mc:Ignorable="d"> x:DataType="viewModels:SettingsViewModel">
<UserControl.Resources>
<helpers:TimeZoneConverter x:Key="TimeZone" />
</UserControl.Resources>
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
</Design.DataContext> </Design.DataContext>
@@ -24,18 +27,24 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Orientation="Vertical" Orientation="Vertical"
Spacing="10"> Spacing="10">
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBlock <TextBlock
Width="250" Classes="h1"
Text="{locale:Locale SettingsTabSystemCore}" />
<StackPanel
Margin="10,0,0,0"
Orientation="Vertical">
<StackPanel
Margin="0,0,0,10"
Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{locale:Locale SettingsTabSystemSystemRegion}" /> Text="{locale:Locale SettingsTabSystemSystemRegion}"
Width="250" />
<ComboBox <ComboBox
Width="350"
HorizontalContentAlignment="Left"
SelectedIndex="{Binding Region}" SelectedIndex="{Binding Region}"
ToolTip.Tip="{locale:Locale RegionTooltip}"> ToolTip.Tip="{locale:Locale RegionTooltip}"
HorizontalContentAlignment="Left"
Width="350">
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
</ComboBoxItem> </ComboBoxItem>
@@ -59,17 +68,19 @@
</ComboBoxItem> </ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel
Margin="0,0,0,10"
Orientation="Horizontal">
<TextBlock <TextBlock
Width="250"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{locale:Locale SettingsTabSystemSystemLanguage}" Text="{locale:Locale SettingsTabSystemSystemLanguage}"
ToolTip.Tip="{locale:Locale LanguageTooltip}" /> ToolTip.Tip="{locale:Locale LanguageTooltip}"
Width="250" />
<ComboBox <ComboBox
Width="350"
HorizontalContentAlignment="Left"
SelectedIndex="{Binding Language}" SelectedIndex="{Binding Language}"
ToolTip.Tip="{locale:Locale LanguageTooltip}"> ToolTip.Tip="{locale:Locale LanguageTooltip}"
HorizontalContentAlignment="Left"
Width="350">
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
</ComboBoxItem> </ComboBoxItem>
@@ -126,63 +137,84 @@
</ComboBoxItem> </ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel
Margin="0,0,0,10"
Orientation="Horizontal">
<TextBlock <TextBlock
Width="250"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{locale:Locale SettingsTabSystemSystemTimeZone}" Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
ToolTip.Tip="{locale:Locale TimezoneTooltip}" /> ToolTip.Tip="{locale:Locale TimezoneTooltip}"
Width="250" />
<AutoCompleteBox <AutoCompleteBox
Name="TimeZoneBox" Name="TimeZoneBox"
Width="350" Width="350"
FilterMode="Contains"
Items="{Binding TimeZones}"
MaxDropDownHeight="500" MaxDropDownHeight="500"
FilterMode="Contains"
ItemsSource="{Binding TimeZones}"
SelectionChanged="TimeZoneBox_OnSelectionChanged" SelectionChanged="TimeZoneBox_OnSelectionChanged"
Text="{Binding Path=TimeZone, Mode=OneWay}" Text="{Binding Path=TimeZone, Mode=OneWay}"
TextChanged="TimeZoneBox_OnTextChanged" TextChanged="TimeZoneBox_OnTextChanged"
ToolTip.Tip="{locale:Locale TimezoneTooltip}" /> ToolTip.Tip="{locale:Locale TimezoneTooltip}"
ValueMemberBinding="{Binding Mode=OneWay, Converter={StaticResource TimeZone}}" />
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel
Margin="0,0,0,10"
Orientation="Horizontal">
<TextBlock <TextBlock
Width="250"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{locale:Locale SettingsTabSystemSystemTime}" Text="{locale:Locale SettingsTabSystemSystemTime}"
ToolTip.Tip="{locale:Locale TimeTooltip}" /> ToolTip.Tip="{locale:Locale TimeTooltip}"
Width="250"/>
<DatePicker <DatePicker
Width="350"
VerticalAlignment="Center" VerticalAlignment="Center"
SelectedDate="{Binding CurrentDate}" SelectedDate="{Binding CurrentDate}"
ToolTip.Tip="{locale:Locale TimeTooltip}" /> ToolTip.Tip="{locale:Locale TimeTooltip}"
Width="350" />
</StackPanel> </StackPanel>
<StackPanel Margin="250,0,0,10" Orientation="Horizontal"> <StackPanel
Margin="250,0,0,10"
Orientation="Horizontal">
<TimePicker <TimePicker
Width="350"
VerticalAlignment="Center" VerticalAlignment="Center"
ClockIdentifier="24HourClock" ClockIdentifier="24HourClock"
SelectedTime="{Binding CurrentTime}" SelectedTime="{Binding CurrentTime}"
Width="350"
ToolTip.Tip="{locale:Locale TimeTooltip}" /> ToolTip.Tip="{locale:Locale TimeTooltip}" />
</StackPanel> </StackPanel>
<CheckBox IsChecked="{Binding EnableVsync}"> <CheckBox IsChecked="{Binding EnableVsync}">
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}" ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" /> <TextBlock
Text="{locale:Locale SettingsTabSystemEnableVsync}"
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}"> <CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}" ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" /> <TextBlock
Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<Separator Height="1" /> <Separator Height="1" />
<StackPanel Orientation="Vertical" Spacing="2"> <StackPanel
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" /> Orientation="Vertical"
<TextBlock Foreground="{DynamicResource SecondaryTextColor}" Text="{locale:Locale SettingsTabSystemHacksNote}" /> Spacing="2">
<TextBlock
Classes="h1"
Text="{locale:Locale SettingsTabSystemHacks}" />
<TextBlock
Foreground="{DynamicResource SecondaryTextColor}"
Text="{locale:Locale SettingsTabSystemHacksNote}" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
Margin="10,0,0,0" Margin="10,0,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Orientation="Vertical"> Orientation="Vertical">
<CheckBox IsChecked="{Binding ExpandDramSize}" ToolTip.Tip="{locale:Locale DRamTooltip}"> <CheckBox
IsChecked="{Binding ExpandDramSize}"
ToolTip.Tip="{locale:Locale DRamTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" /> <TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding IgnoreMissingServices}" ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}"> <CheckBox
IsChecked="{Binding IgnoreMissingServices}"
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" /> <TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>

View File

@@ -1,9 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using System;
using System.Linq;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
@@ -15,15 +11,6 @@ namespace Ryujinx.Ava.UI.Views.Settings
public SettingsSystemView() public SettingsSystemView()
{ {
InitializeComponent(); InitializeComponent();
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
MultiBinding tzMultiBinding = new() { Converter = converter };
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
tzMultiBinding.Bindings.Add(new Binding("Location"));
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
} }
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -39,14 +26,12 @@ namespace Ryujinx.Ava.UI.Views.Settings
} }
} }
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e) private void TimeZoneBox_OnTextChanged(object sender, TextChangedEventArgs e)
{ {
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone) if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
{
{ {
ViewModel.ValidateAndSetTimeZone(timeZone.Location); ViewModel.ValidateAndSetTimeZone(timeZone.Location);
} }
} }
} }
} }
}

View File

@@ -7,7 +7,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
@@ -66,7 +65,7 @@
<ListBox <ListBox
Name="GameList" Name="GameList"
MinHeight="230" MinHeight="230"
Items="{Binding GameDirectories}"> ItemsSource="{Binding GameDirectories}">
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBoxItem"> <Style Selector="ListBoxItem">
<Setter Property="Padding" Value="10" /> <Setter Property="Padding" Value="10" />

View File

@@ -1,7 +1,7 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using System.Collections.Generic; using System.Collections.Generic;
@@ -30,13 +30,16 @@ namespace Ryujinx.Ava.UI.Views.Settings
} }
else else
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (this.GetVisualRoot() is Window window)
{ {
path = await new OpenFolderDialog().ShowAsync(desktop.MainWindow); var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
AllowMultiple = false
});
if (!string.IsNullOrWhiteSpace(path)) if (result.Count > 0)
{ {
ViewModel.GameDirectories.Add(path); ViewModel.GameDirectories.Add(result[0].Path.LocalPath);
ViewModel.DirectoryChanged = true; ViewModel.DirectoryChanged = true;
} }
} }
@@ -61,22 +64,25 @@ namespace Ryujinx.Ava.UI.Views.Settings
public async void BrowseTheme(object sender, RoutedEventArgs e) public async void BrowseTheme(object sender, RoutedEventArgs e)
{ {
var dialog = new OpenFileDialog var window = this.GetVisualRoot() as Window;
var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
AllowMultiple = false, AllowMultiple = false,
}; FileTypeFilter = new List<FilePickerFileType>
dialog.Filters.Add(new FileDialogFilter { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
var file = await dialog.ShowAsync(desktop.MainWindow); new("xml")
if (file != null && file.Length > 0)
{ {
ViewModel.CustomThemePath = file[0]; Patterns = new[] { "*.xaml" },
} AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xaml" },
MimeTypes = new[] { "application/xaml+xml" }
}
}
});
if (result.Count > 0)
{
ViewModel.CustomThemePath = result[0].Path.LocalPath;
} }
} }
} }

View File

@@ -13,7 +13,6 @@
Padding="0" Padding="0"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:CompileBindings="True"
x:DataType="models:TempProfile"> x:DataType="models:TempProfile">
<UserControl.Resources> <UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" /> <helpers:BitmapArrayValueConverter x:Key="ByteImage" />

View File

@@ -12,7 +12,6 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
x:CompileBindings="True"
x:DataType="viewModels:UserFirmwareAvatarSelectorViewModel" x:DataType="viewModels:UserFirmwareAvatarSelectorViewModel"
Focusable="True"> Focusable="True">
<Design.DataContext> <Design.DataContext>
@@ -36,7 +35,7 @@
BorderThickness="0" BorderThickness="0"
SelectedIndex="{Binding SelectedIndex}" SelectedIndex="{Binding SelectedIndex}"
Height="400" Height="400"
Items="{Binding Images}" ItemsSource="{Binding Images}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center"> VerticalAlignment="Center">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
@@ -54,7 +53,7 @@
<Setter Property="MaxWidth" Value="85" /> <Setter Property="MaxWidth" Value="85" />
<Setter Property="MinWidth" Value="85" /> <Setter Property="MinWidth" Value="85" />
</Style> </Style>
<Style Selector="ListBoxItem /template/ Border#SelectionIndicator"> <Style Selector="ListBoxItem /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="70" /> <Setter Property="MinHeight" Value="70" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>

View File

@@ -9,7 +9,6 @@
Focusable="True" Focusable="True"
mc:Ignorable="d" mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView" x:Class="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView"
x:CompileBindings="True"
x:DataType="viewModles:UserProfileImageSelectorViewModel" x:DataType="viewModles:UserProfileImageSelectorViewModel"
Width="500" Width="500"
d:DesignWidth="500"> d:DesignWidth="500">

View File

@@ -1,5 +1,6 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation; using FluentAvalonia.UI.Navigation;
@@ -10,6 +11,7 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using System.Collections.Generic;
using System.IO; using System.IO;
using Image = SixLabors.ImageSharp.Image; using Image = SixLabors.ImageSharp.Image;
@@ -63,35 +65,27 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e) private async void Import_OnClick(object sender, RoutedEventArgs e)
{ {
OpenFileDialog dialog = new(); var window = this.GetVisualRoot() as Window;
dialog.Filters.Add(new FileDialogFilter var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats], AllowMultiple = false,
Extensions = { "jpg", "jpeg", "png", "bmp" }, FileTypeFilter = new List<FilePickerFileType>
{
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
{
Patterns = new[] { "*.jpg", "*.jpeg", "*.png", "*.bmp" },
AppleUniformTypeIdentifiers = new[] { "public.jpeg", "public.png", "com.microsoft.bmp" },
MimeTypes = new[] { "image/jpeg", "image/png", "image/bmp" }
}
}
}); });
dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
dialog.Filters.Add(new FileDialogFilter { Name = "PNG", Extensions = { "png" } });
dialog.Filters.Add(new FileDialogFilter { Name = "BMP", Extensions = { "bmp" } });
dialog.AllowMultiple = false; if (result.Count > 0)
string[] image = await dialog.ShowAsync(((TopLevel)_parent.GetVisualRoot()) as Window);
if (image != null)
{
if (image.Length > 0)
{
string imageFile = image[0];
_profile.Image = ProcessProfileImage(File.ReadAllBytes(imageFile));
if (_profile.Image != null)
{ {
_profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath));
_parent.GoBack(); _parent.GoBack();
} }
} }
}
}
private void GoBack(object sender, RoutedEventArgs e) private void GoBack(object sender, RoutedEventArgs e)
{ {

View File

@@ -12,7 +12,6 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
x:Class="Ryujinx.Ava.UI.Views.User.UserRecovererView" x:Class="Ryujinx.Ava.UI.Views.User.UserRecovererView"
x:CompileBindings="True"
x:DataType="viewModels:UserProfileViewModel" x:DataType="viewModels:UserProfileViewModel"
Focusable="True"> Focusable="True">
<Design.DataContext> <Design.DataContext>
@@ -33,7 +32,7 @@
<ListBox <ListBox
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Items="{Binding LostProfiles}"> ItemsSource="{Binding LostProfiles}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Border <Border

View File

@@ -14,7 +14,6 @@
Height="450" Height="450"
Width="550" Width="550"
x:Class="Ryujinx.Ava.UI.Views.User.UserSaveManagerView" x:Class="Ryujinx.Ava.UI.Views.User.UserSaveManagerView"
x:CompileBindings="True"
x:DataType="viewModels:UserSaveManagerViewModel" x:DataType="viewModels:UserSaveManagerViewModel"
Focusable="True"> Focusable="True">
<Design.DataContext> <Design.DataContext>
@@ -107,8 +106,7 @@
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<ListBox <ListBox
Name="SaveList" Name="SaveList"
VirtualizationMode="None" ItemsSource="{Binding Views}"
Items="{Binding Views}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<ListBox.Styles> <ListBox.Styles>
@@ -117,7 +115,7 @@
<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="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>

View File

@@ -15,7 +15,6 @@
d:DesignWidth="800" d:DesignWidth="800"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True" Focusable="True"
x:CompileBindings="True"
x:DataType="viewModels:UserProfileViewModel"> x:DataType="viewModels:UserProfileViewModel">
<UserControl.Resources> <UserControl.Resources>
<helpers:BitmapArrayValueConverter x:Key="ByteImage" /> <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
@@ -38,7 +37,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
SelectionChanged="ProfilesList_SelectionChanged" SelectionChanged="ProfilesList_SelectionChanged"
Background="Transparent" Background="Transparent"
Items="{Binding Profiles}"> ItemsSource="{Binding Profiles}">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<flex:FlexPanel <flex:FlexPanel
@@ -53,7 +52,7 @@
<Setter Property="Margin" Value="5 5 0 5" /> <Setter Property="Margin" Value="5 5 0 5" />
<Setter Property="CornerRadius" Value="5" /> <Setter Property="CornerRadius" Value="5" />
</Style> </Style>
<Style Selector="Border#SelectionIndicator"> <Style Selector="Rectangle#SelectionIndicator">
<Setter Property="Opacity" Value="0" /> <Setter Property="Opacity" Value="0" />
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
@@ -61,8 +60,8 @@
<DataTemplate <DataTemplate
DataType="models:UserProfile"> DataType="models:UserProfile">
<Grid <Grid
PointerEnter="Grid_PointerEntered" PointerEntered="Grid_PointerEntered"
PointerLeave="Grid_OnPointerExited"> PointerExited="Grid_OnPointerExited">
<Border <Border
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"

View File

@@ -13,7 +13,6 @@
Margin="0,-12,0,0" Margin="0,-12,0,0"
d:DesignHeight="260" d:DesignHeight="260"
d:DesignWidth="550" d:DesignWidth="550"
x:CompileBindings="True"
x:DataType="viewModel:AboutWindowViewModel" x:DataType="viewModel:AboutWindowViewModel"
Focusable="True" Focusable="True"
mc:Ignorable="d"> mc:Ignorable="d">
@@ -64,14 +63,14 @@
FontWeight="Bold" FontWeight="Bold"
Text="Ryujinx" Text="Ryujinx"
TextAlignment="Center" TextAlignment="Center"
Width="100" /> Width="110" />
<TextBlock <TextBlock
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="11" FontSize="11"
Text="(REE-YOU-JINX)" Text="(REE-YOU-JINX)"
TextAlignment="Center" TextAlignment="Center"
Width="100" /> Width="110" />
</flex:FlexPanel> </flex:FlexPanel>
</Grid> </Grid>
<TextBlock <TextBlock

View File

@@ -10,6 +10,7 @@
d:DesignWidth="400" d:DesignWidth="400"
d:DesignHeight="350" d:DesignHeight="350"
x:Class="Ryujinx.Ava.UI.Windows.AmiiboWindow" x:Class="Ryujinx.Ava.UI.Windows.AmiiboWindow"
x:DataType="viewModels:AmiiboWindowViewModel"
CanResize="False" CanResize="False"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Width="800" Width="800"
@@ -35,11 +36,11 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left"> <StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboSeriesLabel}" /> <TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboSeriesLabel}" />
<ComboBox SelectedIndex="{Binding SeriesSelectedIndex}" Items="{Binding AmiiboSeries}" MinWidth="100" /> <ComboBox SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="100" />
</StackPanel> </StackPanel>
<StackPanel Spacing="10" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Spacing="10" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboCharacterLabel}" /> <TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboCharacterLabel}" />
<ComboBox SelectedIndex="{Binding AmiiboSelectedIndex}" MinWidth="100" Items="{Binding AmiiboList}" /> <ComboBox SelectedIndex="{Binding AmiiboSelectedIndex}" MinWidth="100" ItemsSource="{Binding AmiiboList}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<StackPanel Margin="20" Grid.Row="2"> <StackPanel Margin="20" Grid.Row="2">

View File

@@ -40,7 +40,7 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
LineHeight="18" LineHeight="18"
Text="{Binding Heading}" Text="{ReflectionBinding Heading}"
TextAlignment="Center" TextAlignment="Center"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -61,7 +61,7 @@
MinWidth="160" MinWidth="160"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding BuildId}" Text="{ReflectionBinding BuildId}"
IsReadOnly="True" /> IsReadOnly="True" />
<Border <Border
Grid.Row="3" Grid.Row="3"
@@ -77,7 +77,7 @@
MinHeight="300" MinHeight="300"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Items="{Binding LoadedCheats}"> ItemsSource="{ReflectionBinding LoadedCheats}">
<TreeView.Styles> <TreeView.Styles>
<Styles> <Styles>
<Style Selector="TreeViewItem:empty /template/ ItemsPresenter"> <Style Selector="TreeViewItem:empty /template/ ItemsPresenter">
@@ -120,15 +120,15 @@
Name="SaveButton" Name="SaveButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{Binding Save}" Command="{ReflectionBinding Save}"
IsVisible="{Binding !NoCheatsFound}"> IsVisible="{ReflectionBinding !NoCheatsFound}">
<TextBlock Text="{locale:Locale SettingsButtonSave}" /> <TextBlock Text="{locale:Locale SettingsButtonSave}" />
</Button> </Button>
<Button <Button
Name="CancelButton" Name="CancelButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Command="{Binding Close}"> Command="{ReflectionBinding Close}">
<TextBlock Text="{locale:Locale InputDialogCancel}" /> <TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button> </Button>
</DockPanel> </DockPanel>

Some files were not shown because too many files have changed in this diff Show More