Compare commits

...

23 Commits

Author SHA1 Message Date
Evan Husted
d23fc437eb Merge 8a6f806dda into 920933bc9f 2025-02-18 18:10:56 -06:00
Willians
920933bc9f Small PT-BR update (#688) 2025-02-18 17:29:58 -06:00
Evan Husted
8a6f806dda Merge branch 'master' into xeyes 2025-02-12 16:34:47 -06:00
Evan Husted
15d589c455 Merge branch 'master' into xeyes 2025-02-11 22:55:43 -06:00
Evan Husted
3262020e18 Merge branch 'master' into xeyes 2025-02-07 21:35:51 -06:00
Evan Husted
a3afebd3a2 Merge branch 'master' into xeyes 2025-02-05 14:59:03 -06:00
Evan Husted
24e88e2485 Merge branch 'master' into xeyes 2025-01-29 02:48:51 -06:00
Evan Husted
3b447b764e Merge branch 'master' into xeyes 2025-01-28 01:45:49 -06:00
Evan Husted
849fd0199e Merge branch 'master' into xeyes 2025-01-26 17:33:58 -06:00
Evan Husted
57e26114e8 Merge branch 'master' into xeyes 2025-01-25 21:56:40 -06:00
Evan Husted
6a283190b3 Add the controller image back 2025-01-24 22:24:02 -06:00
MutantAura
85547874c8 Consolidate most logic into StickVisualizer. 2025-01-24 20:08:58 -06:00
MutantAura
16ca8e5005 Move most logic into new StickVisualizer class and add keyboard support. 2025-01-24 20:01:36 -06:00
MutantAura
cfa5ad0757 Simplfy clamping and fix bug on window close. 2025-01-24 19:58:17 -06:00
MutantAura
43ece083b2 Move some backing fields to match others.
formatting pt.2
2025-01-24 19:57:11 -06:00
MutantAura
e1f5c501b0 Fix some issues with stick magnitude. 2025-01-24 19:56:21 -06:00
MutantAura
ffe366d953 Cleanup AXAML and hide sticks when only one is present on guest controller. 2025-01-24 19:52:57 -06:00
MutantAura
75c7a29278 style and analyzers 2025-01-24 19:52:52 -06:00
MutantAura
3a0d9c1435 whitespace 2025-01-24 19:52:47 -06:00
MutantAura
93d1476a2a Remove unused grid definitions. 2025-01-24 19:52:39 -06:00
MutantAura
ce13830063 Clean up some magic numbers between code and axaml. 2025-01-24 19:52:24 -06:00
MutantAura
aa3f2824e0 Polish the aesthetic and include deadzone visualization. 2025-01-24 19:51:44 -06:00
MutantAura
d2bb580aea Initial implementation of analog stick visualization. 2025-01-24 19:50:09 -06:00
8 changed files with 509 additions and 29 deletions

View File

@@ -10412,7 +10412,7 @@
"ko_KR": "연동 해제",
"no_NO": "Ikke bundet",
"pl_PL": "",
"pt_BR": "",
"pt_BR": "Não Atribuído",
"ru_RU": "Не привязано",
"sv_SE": "Obunden",
"th_TH": "",
@@ -16212,7 +16212,7 @@
"ko_KR": "시스템 시간 변경",
"no_NO": "Endre systemtid",
"pl_PL": "Zmień czas systemowy",
"pt_BR": "Mudar a Hora do Sistema",
"pt_BR": "Mudar a Data e Hora do Sistema",
"ru_RU": "Меняет системное время системы",
"sv_SE": "Ändra systemtid",
"th_TH": "เปลี่ยนเวลาของระบบ",
@@ -16387,7 +16387,7 @@
"ko_KR": "게스트 메모리 매핑 및 접속 방법을 변경합니다. 에뮬레이트된 CPU 성능에 큰 영향을 미칩니다.\n\n모르면 호스트 확인 안 함으로 설정합니다.",
"no_NO": "Endre hvordan gjesteminne tilordnes og åpnes. Påvirker emulator CPU-ytelsen veldig mye.\n\nSett til HOST UNCHECKED hvis usikker.",
"pl_PL": "Zmień sposób mapowania i uzyskiwania dostępu do pamięci gości. Znacznie wpływa na wydajność emulowanego procesora.\n\nUstaw na HOST UNCHECKED, jeśli nie masz pewności.",
"pt_BR": "Altera como a memória do convidado é mapeada e acessada. Afeta muito o desempenho da CPU emulada.\n\nDefina como HOST UNCHECKED se não tiver certeza.",
"pt_BR": "Altera como a memória do convidado é mapeada e acessada. Afeta muito o desempenho da CPU emulada.\n\nDefina como HÓSPEDE SEM VERIFICAÇÃO se não tiver certeza.",
"ru_RU": "Меняет разметку и доступ к гостевой памяти. Значительно влияет на производительность процессора.\n\nРекомендуется оставить \"Хост не установлен\"",
"sv_SE": "Ändra hur gästminne mappas och ges åtkomst till. Påverkar emulerad CPU-prestanda mycket.\n\nStäll in till \"Värd inte kontrollerad\" om du är osäker.",
"th_TH": "เปลี่ยนวิธีการเข้าถึงหน่วยความจำของผู้เยี่ยมชม ส่งผลอย่างมากต่อประสิทธิภาพการทำงานของ CPU ที่จำลอง\n\nตั้งค่าเป็น ไม่ได้ตรวจสอบโฮสต์ หากคุณไม่แน่ใจ",
@@ -16512,7 +16512,7 @@
"ko_KR": "Switch 개발 모델을 모방하기 위해 8GB DRAM이 포함된 대체 메모리 모드를 활용합니다.\n\n이는 고해상도 텍스처 팩 또는 4K 해상도 모드에만 유용합니다. 성능을 개선하지 않습니다.\n\n모르면 끔으로 두세요.",
"no_NO": "Bruker en alternativ minnemodus med 8GiB i DRAM for og etterligne Switch utvikler modeller.\n\nDette er bare nyttig for teksturpakker eller 4k oppløsningsmoduler. Forbedrer IKKE ytelsen.\n\nLa AV hvis usikker.",
"pl_PL": "Wykorzystuje alternatywny układ MemoryMode, aby naśladować model rozwojowy Switcha.\n\nJest to przydatne tylko w przypadku pakietów tekstur o wyższej rozdzielczości lub modów w rozdzielczości 4k. NIE poprawia wydajności.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
"pt_BR": "Utiliza um modo de memória alternativo com 8 GB de DRAM para imitar um modelo de desenvolvimento do Switch.\n\nIsso só é útil para pacotes de textura de alta resolução ou mods de resolução 4k. NÃO melhora o desempenho.\n\nDeixe OFF se não tiver certeza.",
"pt_BR": "Utiliza um modo de memória alternativo com 6, 8 ou 12 GB de DRAM para imitar um modelo de desenvolvimento do Switch.\n\nIsso só é útil para pacotes de textura de alta resolução ou mods de resolução 4k. NÃO melhora o desempenho.\n\nDeixe em 4 GB se não tiver certeza.",
"ru_RU": "Использует альтернативный макет MemoryMode для имитации использования Nintendo Switch в режиме разработчика.\n\nПолезно только для пакетов текстур с высоким разрешением или модов добавляющих разрешение 4К. Не улучшает производительность.\n\nРекомендуется оставить выключенным.",
"sv_SE": "Använder ett alternativt minnesläge med 8GiB av DRAM för att efterlikna en utvecklingsmodell av Switch.\n\nDetta är endast användbart för texturpaket med högre upplösning eller moddar för 4k-upplösning. Det förbättrar INTE prestandan.\n\nLämna AV om du är osäker.",
"th_TH": "ใช้รูปแบบ MemoryMode ทางเลือกเพื่อเลียนแบบโมเดลการพัฒนาสวิตช์\n\nสิ่งนี้มีประโยชน์สำหรับแพ็กพื้นผิวที่มีความละเอียดสูงกว่าหรือม็อดที่มีความละเอียด 4k เท่านั้น\n\nปล่อยให้ปิดหากคุณไม่แน่ใจ",
@@ -16637,7 +16637,7 @@
"ko_KR": "후속 실행 시 끊김 현상을 줄이는 디스크 셰이더 캐시를 저장합니다.\n\n모르면 켬으로 두세요.",
"no_NO": "Lagrer en disk shader cache som reduserer hakking jo flere ganger du spiller.\n\nLa være PÅ om usikker.",
"pl_PL": "Zapisuje pamięć podręczną shaderów na dysku, co zmniejsza zacinanie się w kolejnych uruchomieniach.\n\nPozostaw WŁĄCZONE, jeśli nie masz pewności.",
"pt_BR": "Salva um cache de shader de disco que reduz a trepidação em execuções subsequentes.\n\nDeixe LIGADO se não tiver certeza.",
"pt_BR": "Salva um cache de shader no disco que reduz a trepidação em execuções subsequentes.\n\nDeixe LIGADO se não tiver certeza.",
"ru_RU": "Сохраняет кэш шейдеров на диске, для уменьшения статтеров при последующих запусках.\n\nРекомендуется оставить включенным.",
"sv_SE": "Sparar en disk shader cache som minskar stuttering i efterföljande körningar.\n\nLämna PÅ om du är osäker.",
"th_TH": "บันทึกแคชแสงเงาของดิสก์ซึ่งช่วยลดการกระตุกในการรันครั้งต่อๆ ไป\n\nเปิดทิ้งไว้หากคุณไม่แน่ใจ",

View File

@@ -0,0 +1,260 @@
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Models.Input
{
public class StickVisualizer : BaseModel, IDisposable
{
public const int DrawStickPollRate = 50; // Milliseconds per poll.
public const int DrawStickCircumference = 5;
public const float DrawStickScaleFactor = DrawStickCanvasCenter;
public const int DrawStickCanvasSize = 100;
public const int DrawStickBorderSize = DrawStickCanvasSize + 5;
public const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2;
public const float MaxVectorLength = DrawStickCanvasSize / 2;
public CancellationTokenSource PollTokenSource;
public CancellationToken PollToken;
private static float _vectorLength;
private static float _vectorMultiplier;
private bool disposedValue;
private DeviceType _type;
public DeviceType Type
{
get => _type;
set
{
_type = value;
OnPropertyChanged();
}
}
private GamepadInputConfig _gamepadConfig;
public GamepadInputConfig GamepadConfig
{
get => _gamepadConfig;
set
{
_gamepadConfig = value;
OnPropertyChanged();
}
}
private KeyboardInputConfig _keyboardConfig;
public KeyboardInputConfig KeyboardConfig
{
get => _keyboardConfig;
set
{
_keyboardConfig = value;
OnPropertyChanged();
}
}
private (float, float) _uiStickLeft;
public (float, float) UiStickLeft
{
get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor);
set
{
_uiStickLeft = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UiStickRightX));
OnPropertyChanged(nameof(UiStickRightY));
OnPropertyChanged(nameof(UiDeadzoneRight));
}
}
private (float, float) _uiStickRight;
public (float, float) UiStickRight
{
get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor);
set
{
_uiStickRight = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UiStickLeftX));
OnPropertyChanged(nameof(UiStickLeftY));
OnPropertyChanged(nameof(UiDeadzoneLeft));
}
}
public float UiStickLeftX => ClampVector(UiStickLeft).Item1;
public float UiStickLeftY => ClampVector(UiStickLeft).Item2;
public float UiStickRightX => ClampVector(UiStickRight).Item1;
public float UiStickRightY => ClampVector(UiStickRight).Item2;
public int UiStickCircumference => DrawStickCircumference;
public int UiCanvasSize => DrawStickCanvasSize;
public int UiStickBorderSize => DrawStickBorderSize;
public float? UiDeadzoneLeft => _gamepadConfig?.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference;
public float? UiDeadzoneRight => _gamepadConfig?.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference;
private InputViewModel Parent;
public StickVisualizer(InputViewModel parent)
{
Parent = parent;
PollTokenSource = new CancellationTokenSource();
PollToken = PollTokenSource.Token;
Task.Run(Initialize, PollToken);
}
public void UpdateConfig(object config)
{
if (config is ControllerInputViewModel padConfig)
{
GamepadConfig = padConfig.Config;
Type = DeviceType.Controller;
return;
}
else if (config is KeyboardInputViewModel keyConfig)
{
KeyboardConfig = keyConfig.Config;
Type = DeviceType.Keyboard;
return;
}
Type = DeviceType.None;
}
public async Task Initialize()
{
(float, float) leftBuffer;
(float, float) rightBuffer;
while (!PollToken.IsCancellationRequested)
{
leftBuffer = (0f, 0f);
rightBuffer = (0f, 0f);
switch (Type)
{
case DeviceType.Keyboard:
IKeyboard keyboard = (IKeyboard)Parent.AvaloniaKeyboardDriver.GetGamepad("0");
if (keyboard != null)
{
KeyboardStateSnapshot snapshot = keyboard.GetKeyboardStateSnapshot();
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickRight))
{
leftBuffer.Item1 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickLeft))
{
leftBuffer.Item1 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickUp))
{
leftBuffer.Item2 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickDown))
{
leftBuffer.Item2 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickRight))
{
rightBuffer.Item1 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickLeft))
{
rightBuffer.Item1 -= 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickUp))
{
rightBuffer.Item2 += 1;
}
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickDown))
{
rightBuffer.Item2 -= 1;
}
UiStickLeft = leftBuffer;
UiStickRight = rightBuffer;
}
break;
case DeviceType.Controller:
IGamepad controller = Parent.SelectedGamepad;
if (controller != null)
{
leftBuffer = controller.GetStick((StickInputId)GamepadConfig.LeftJoystick);
rightBuffer = controller.GetStick((StickInputId)GamepadConfig.RightJoystick);
}
break;
case DeviceType.None:
break;
default:
throw new ArgumentException($"Unable to poll device type \"{Type}\"");
}
UiStickLeft = leftBuffer;
UiStickRight = rightBuffer;
await Task.Delay(DrawStickPollRate, PollToken);
}
PollTokenSource.Dispose();
}
public static (float, float) ClampVector((float, float) vect)
{
_vectorMultiplier = 1;
_vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2));
if (_vectorLength > MaxVectorLength)
{
_vectorMultiplier = MaxVectorLength / _vectorLength;
}
vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter;
vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter;
return vect;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
PollTokenSource.Cancel();
}
KeyboardConfig = null;
GamepadConfig = null;
Parent = null;
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View File

@@ -1,5 +1,9 @@
using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Common.Utilities;
@@ -10,8 +14,30 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class ControllerInputViewModel : BaseModel
{
[ObservableProperty] private GamepadInputConfig _config;
private GamepadInputConfig _config;
public GamepadInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
set
{
_visualizer = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
@@ -37,14 +63,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image;
public InputViewModel ParentModel { get; }
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer)
{
ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
config.PropertyChanged += (_, args) =>

View File

@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller;
private string _controllerImage;
private int _device;
[ObservableProperty] private object _configViewModel;
private object _configViewModel;
[ObservableProperty] private string _profileName;
private bool _isLoaded;
@@ -74,6 +74,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
}
}
public StickVisualizer VisualStick { get; private set; }
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
@@ -94,6 +95,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsModified { get; set; }
public event Action NotifyChangesEvent;
public object ConfigViewModel
{
get => _configViewModel;
set
{
_configViewModel = value;
VisualStick.UpdateConfig(value);
OnPropertyChanged();
}
}
public PlayerIndex PlayerIdChoose
{
get => _playerIdChoose;
@@ -269,6 +283,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
Devices = [];
ProfilesList = [];
DeviceList = [];
VisualStick = new StickVisualizer(this);
ControllerImage = ProControllerResource;
@@ -289,12 +304,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (Config is StandardKeyboardInputConfig keyboardInputConfig)
{
ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig));
ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig), VisualStick);
}
if (Config is StandardControllerInputConfig controllerInputConfig)
{
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick);
}
}
@@ -893,6 +908,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
_mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates();
VisualStick.Dispose();
SelectedGamepad?.Dispose();
AvaloniaKeyboardDriver.Dispose();

View File

@@ -6,7 +6,29 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class KeyboardInputViewModel : BaseModel
{
[ObservableProperty] private KeyboardInputConfig _config;
private KeyboardInputConfig _config;
public KeyboardInputConfig Config
{
get => _config;
set
{
_config = value;
OnPropertyChanged();
}
}
private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
get => _visualizer;
set
{
_visualizer = value;
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
@@ -38,9 +60,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public readonly InputViewModel ParentModel;
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config)
public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config, StickVisualizer visualizer)
{
ParentModel = model;
Visualizer = visualizer;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
Config = config;

View File

@@ -316,17 +316,103 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!-- Controller Picture -->
<Image
Margin="0,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0,10"
MinHeight="90">
<StackPanel Orientation="Vertical">
<Image
Margin="5,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<StackPanel
Margin="10"
Orientation="Horizontal"
Spacing="20"
HorizontalAlignment="Center">
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsLeft}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Gray"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneLeft}"
Width="{Binding Visualizer.UiDeadzoneLeft}" />
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickLeftY}"
Canvas.Left="{Binding Visualizer.UiStickLeftX}" />
</Canvas>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsRight}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}" />
<Ellipse
HorizontalAlignment="Center"
Fill="Gray"
Opacity="100"
Height="{Binding Visualizer.UiDeadzoneRight}"
Width="{Binding Visualizer.UiDeadzoneRight}" />
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickRightY}"
Canvas.Left="{Binding Visualizer.UiStickRightX}" />
</Canvas>
</Border>
</StackPanel>
</StackPanel>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5">
<StackPanel
Margin="8"
Orientation="Vertical">
@@ -345,8 +431,8 @@
Minimum="0"
Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" />
<TextBlock
Width="25"
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
Width="25"
Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" />
</StackPanel>
<StackPanel
Orientation="Vertical"

View File

@@ -309,12 +309,79 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!-- Controller Picture -->
<Image
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Margin="0,10"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
MinHeight="90">
<StackPanel
Margin="10"
Orientation="Horizontal"
Spacing="20"
HorizontalAlignment="Center">
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsLeft}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}"/>
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickLeftY}"
Canvas.Left="{Binding Visualizer.UiStickLeftX}" />
</Canvas>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
CornerRadius="5"
Height="{Binding Visualizer.UiStickBorderSize}"
Width="{Binding Visualizer.UiStickBorderSize}"
IsVisible="{Binding IsRight}">
<Canvas
Background="{DynamicResource ThemeBackgroundColor}"
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}">
<Grid
Height="{Binding Visualizer.UiCanvasSize}"
Width="{Binding Visualizer.UiCanvasSize}"
Background="{DynamicResource ThemeBackgroundColor}">
<Ellipse
HorizontalAlignment="Center"
Stroke="Black"
StrokeThickness="1"
Width="{Binding Visualizer.UiCanvasSize}"
Height="{Binding Visualizer.UiCanvasSize}"/>
</Grid>
<Ellipse
Fill="Red"
Width="{Binding Visualizer.UiStickCircumference}"
Height="{Binding Visualizer.UiStickCircumference}"
Canvas.Bottom="{Binding Visualizer.UiStickRightY}"
Canvas.Left="{Binding Visualizer.UiStickRightX}" />
</Canvas>
</Border>
</StackPanel>
</Border>
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"

View File

@@ -12,7 +12,7 @@
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
Width="1100"
Height="768"
Height="850"
MinWidth="800"
MinHeight="480"
WindowStartupLocation="CenterOwner"