Compare commits

..

7 Commits

Author SHA1 Message Date
Narugakuruga
bdc4fa81f2 Add Simplified Chinese to Avalonia (V2) (#3416)
* Add files via upload

* Update Ryujinx.Ava.csproj

* Update MainWindow.axaml
2022-06-25 17:03:48 +02:00
gdkchan
625f5fb88a Account for pool change on texture bindings cache (#3420)
* Account for pool change on texture bindings cache

* Reduce the number of checks needed
2022-06-25 16:52:38 +02:00
Mary
2382717600 timezone: Fix regression caused by #3361 (#3418)
Because of that PR, TimeZoneRule was bigger than 0x4000 thanks to a
misuse of a constant.

This commit address this issue and add a new unit test to ensure the size of
TimeZoneRule is 0x4000 bytes.

Also address suggestions that were lost on the original PR.
2022-06-24 21:11:56 +02:00
Mary
30ee70a9bc time: Make TimeZoneRule blittable and avoid copies (#3361)
* time: Make TimeZoneRule blittable and avoid copies

This drastically reduce overhead of using TimeZoneRule around the
codebase.

Effect on games is unknown

* Add missing Box type

* Ensure we clean the structure still

This doesn't perform any copies

* Address gdkchan's comments

* Simplify Box
2022-06-24 19:04:57 +02:00
gdkchan
232b1012b0 Fix ThreadingLock deadlock on invalid access and TerminateProcess (#3407) 2022-06-24 02:53:16 +02:00
gdkchan
e747f5cd83 Ensure texture ID is valid before getting texture descriptor (#3406) 2022-06-24 02:41:57 +02:00
Ac_K
8aff17a93c UI: Some Avalonia cleanup (#3358) 2022-06-23 15:59:02 -03:00
35 changed files with 1934 additions and 915 deletions

View File

@@ -1,8 +1,8 @@
<Application <Application
x:Class="Ryujinx.Ava.App" x:Class="Ryujinx.Ava.App"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:sty="using:FluentAvalonia.Styling" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:sty="using:FluentAvalonia.Styling">
<Application.Styles> <Application.Styles>
<sty:FluentAvaloniaTheme UseSystemThemeOnWindows="False" /> <sty:FluentAvaloniaTheme UseSystemThemeOnWindows="False" />
</Application.Styles> </Application.Styles>

View File

@@ -2,7 +2,6 @@ using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Threading;
using FluentAvalonia.Styling; using FluentAvalonia.Styling;
using Ryujinx.Ava.Ui.Windows; using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common; using Ryujinx.Common;
@@ -13,7 +12,7 @@ using System.IO;
namespace Ryujinx.Ava namespace Ryujinx.Ava
{ {
public class App : Avalonia.Application public class App : Application
{ {
public override void Initialize() public override void Initialize()
{ {
@@ -46,7 +45,7 @@ namespace Ryujinx.Ava
private void ShowRestartDialog() private void ShowRestartDialog()
{ {
// TODO. Implement Restart Dialog when SettingsWindow is implemented. // TODO: Implement Restart Dialog when SettingsWindow is implemented.
} }
private void ThemeChanged_Event(object sender, ReactiveEventArgs<string> e) private void ThemeChanged_Event(object sender, ReactiveEventArgs<string> e)

View File

@@ -57,7 +57,7 @@ namespace Ryujinx.Ava
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None); private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
private readonly AccountManager _accountManager; private readonly AccountManager _accountManager;
private UserChannelPersistence _userChannelPersistence; private readonly UserChannelPersistence _userChannelPersistence;
private readonly InputManager _inputManager; private readonly InputManager _inputManager;
@@ -82,7 +82,6 @@ namespace Ryujinx.Ava
private bool _dialogShown; private bool _dialogShown;
private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution; private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
private KeyboardStateSnapshot _lastKeyboardSnapshot;
private readonly CancellationTokenSource _gpuCancellationTokenSource; private readonly CancellationTokenSource _gpuCancellationTokenSource;
@@ -126,7 +125,6 @@ namespace Ryujinx.Ava
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel; _glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
_inputManager.SetMouseDriver(new AvaloniaMouseDriver(renderer)); _inputManager.SetMouseDriver(new AvaloniaMouseDriver(renderer));
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0"); _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
_lastKeyboardSnapshot = _keyboardInterface.GetKeyboardStateSnapshot();
NpadManager = _inputManager.CreateNpadManager(); NpadManager = _inputManager.CreateNpadManager();
TouchScreenManager = _inputManager.CreateTouchScreenManager(); TouchScreenManager = _inputManager.CreateTouchScreenManager();
@@ -722,9 +720,7 @@ namespace Ryujinx.Ava
} }
} }
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GB : HLE.MemoryConfiguration.MemoryConfiguration4GB;
? HLE.MemoryConfiguration.MemoryConfiguration6GB
: HLE.MemoryConfiguration.MemoryConfiguration4GB;
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
@@ -898,7 +894,7 @@ namespace Ryujinx.Ava
} }
} }
private void HandleScreenState(KeyboardStateSnapshot keyboard, KeyboardStateSnapshot lastKeyboard) private void HandleScreenState()
{ {
if (ConfigurationState.Instance.Hid.EnableMouse) if (ConfigurationState.Instance.Hid.EnableMouse)
{ {
@@ -935,19 +931,12 @@ namespace Ryujinx.Ava
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
KeyboardStateSnapshot keyboard = _keyboardInterface.GetKeyboardStateSnapshot(); HandleScreenState();
HandleScreenState(keyboard, _lastKeyboardSnapshot); if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen)
if (keyboard.IsPressed(Key.Delete))
{
if (_parent.WindowState != WindowState.FullScreen)
{ {
Ptc.Continue(); Ptc.Continue();
} }
}
_lastKeyboardSnapshot = keyboard;
}); });
} }

View File

@@ -0,0 +1,552 @@
{
"MenuBarFileOpenApplet": "打开小程序",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的Mii小程序",
"SettingsTabInputDirectMouseAccess": "直通鼠标操作",
"SettingsTabSystemMemoryManagerMode": "内存管理模式:",
"SettingsTabSystemMemoryManagerModeSoftware": "软件",
"SettingsTabSystemMemoryManagerModeHost": "本机 (快速)",
"SettingsTabSystemMemoryManagerModeHostUnchecked": "跳过检查的本机 (最快速)",
"MenuBarFile": "文件(_F)",
"MenuBarFileOpenFromFile": "加载文件中的程序(_L)",
"MenuBarFileOpenUnpacked": "加载解包后的游戏(_U)",
"MenuBarFileOpenEmuFolder": "打开Ryujinx文件夹",
"MenuBarFileOpenLogsFolder": "打开日志文件夹",
"MenuBarFileExit": "退出(_E)",
"MenuBarOptions": "选项",
"MenuBarOptionsToggleFullscreen": "切换全屏",
"MenuBarOptionsStartGamesInFullscreen": "以全屏模式启动游戏",
"MenuBarOptionsStopEmulation": "中止模拟",
"MenuBarOptionsSettings": "设置(_S)",
"MenuBarOptionsManageUserProfiles": "管理用户账户(_M)",
"MenuBarActions": "行动(_A)",
"MenuBarOptionsSimulateWakeUpMessage": "模拟唤醒消息",
"MenuBarActionsScanAmiibo": "扫描Amiibo",
"MenuBarTools": "工具(_T)",
"MenuBarToolsInstallFirmware": "安装固件",
"MenuBarFileToolsInstallFirmwareFromFile": "从 XCI 或 ZIP 安装固件",
"MenuBarFileToolsInstallFirmwareFromDirectory": "从文件夹安装固件",
"MenuBarHelp": "帮助",
"MenuBarHelpCheckForUpdates": "检查更新",
"MenuBarHelpAbout": "关于",
"MenuSearch": "搜索...",
"GameListHeaderFavorite": "收藏",
"GameListHeaderIcon": "图标",
"GameListHeaderApplication": "名称",
"GameListHeaderDeveloper": "制作商",
"GameListHeaderVersion": "版本",
"GameListHeaderTimePlayed": "游玩时间",
"GameListHeaderLastPlayed": "上次游玩",
"GameListHeaderFileExtension": "扩展名",
"GameListHeaderFileSize": "大小",
"GameListHeaderPath": "路径",
"GameListContextMenuOpenUserSaveDirectory": "打开应用存档目录",
"GameListContextMenuOpenUserSaveDirectoryToolTip": "打开储存游戏存档的目录",
"GameListContextMenuOpenUserDeviceDirectory": "打开应用系统目录",
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "打开包含游戏系统设置的目录",
"GameListContextMenuOpenUserBcatDirectory": "打开BCAT目录",
"GameListContextMenuOpenUserBcatDirectoryToolTip": "打开包含游戏BCAT数据的目录",
"GameListContextMenuManageTitleUpdates": "管理游戏更新",
"GameListContextMenuManageTitleUpdatesToolTip": "打开更新管理窗口",
"GameListContextMenuManageDlc": "管理DLC",
"GameListContextMenuManageDlcToolTip": "打开 DLC 管理窗口",
"GameListContextMenuOpenModsDirectory": "打开MOD目录",
"GameListContextMenuOpenModsDirectoryToolTip": "打开存放游戏MOD的目录",
"GameListContextMenuCacheManagement": "缓存管理",
"GameListContextMenuCacheManagementPurgePptc": "清除 PPTC 缓存",
"GameListContextMenuCacheManagementPurgePptcToolTip": "删除游戏的 PPTC 缓存",
"GameListContextMenuCacheManagementPurgeShaderCache": "清除着色器缓存",
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "删除游戏的着色器缓存",
"GameListContextMenuCacheManagementOpenPptcDirectory": "打开 PPTC 目录",
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "打开包含游戏 PPTC 缓存的目录",
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "打开着色器缓存目录",
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "打开包含应用程序着色器缓存的目录",
"GameListContextMenuExtractData": "提取数据",
"GameListContextMenuExtractDataExeFS": "ExeFS",
"GameListContextMenuExtractDataExeFSToolTip": "从游戏的当前状态中提取 ExeFS 分区(包括更新)",
"GameListContextMenuExtractDataRomFS": "RomFS",
"GameListContextMenuExtractDataRomFSToolTip": "从游戏的当前状态中提取 RomFS 分区(包括更新)",
"GameListContextMenuExtractDataLogo": "图标",
"GameListContextMenuExtractDataLogoToolTip": "从游戏的当前状态中提取图标(包括更新)",
"StatusBarGamesLoaded": "{0}/{1} 游戏加载完成",
"StatusBarSystemVersion": "系统版本: {0}",
"Settings": "设置",
"SettingsTabGeneral": "用户界面",
"SettingsTabGeneralGeneral": "常规",
"SettingsTabGeneralEnableDiscordRichPresence": "启用Discord在线状态展示",
"SettingsTabGeneralCheckUpdatesOnLaunch": "自动检查更新",
"SettingsTabGeneralShowConfirmExitDialog": "显示 \"确认退出\" 对话框",
"SettingsTabGeneralHideCursorOnIdle": "空闲时隐藏鼠标",
"SettingsTabGeneralGameDirectories": "游戏目录",
"SettingsTabGeneralAdd": "添加",
"SettingsTabGeneralRemove": "删除",
"SettingsTabSystem": "系统",
"SettingsTabSystemCore": "核心",
"SettingsTabSystemSystemRegion": "系统区域:",
"SettingsTabSystemSystemRegionJapan": "日本",
"SettingsTabSystemSystemRegionUSA": "美国",
"SettingsTabSystemSystemRegionEurope": "欧洲",
"SettingsTabSystemSystemRegionAustralia": "澳大利亚",
"SettingsTabSystemSystemRegionChina": "中国",
"SettingsTabSystemSystemRegionKorea": "韩国",
"SettingsTabSystemSystemRegionTaiwan": "台湾地区",
"SettingsTabSystemSystemLanguage": "系统语言:",
"SettingsTabSystemSystemLanguageJapanese": "日语",
"SettingsTabSystemSystemLanguageAmericanEnglish": "美式英语",
"SettingsTabSystemSystemLanguageFrench": "法语",
"SettingsTabSystemSystemLanguageGerman": "德语",
"SettingsTabSystemSystemLanguageItalian": "意大利语",
"SettingsTabSystemSystemLanguageSpanish": "西班牙语",
"SettingsTabSystemSystemLanguageChinese": "中文(简体)",
"SettingsTabSystemSystemLanguageKorean": "韩语",
"SettingsTabSystemSystemLanguageDutch": "荷兰语",
"SettingsTabSystemSystemLanguagePortuguese": "葡萄牙语",
"SettingsTabSystemSystemLanguageRussian": "俄语",
"SettingsTabSystemSystemLanguageTaiwanese": "中文(繁体)",
"SettingsTabSystemSystemLanguageBritishEnglish": "英式英语",
"SettingsTabSystemSystemLanguageCanadianFrench": "加拿大法语",
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "拉美西班牙语",
"SettingsTabSystemSystemLanguageSimplifiedChinese": "简体中文(推荐)",
"SettingsTabSystemSystemLanguageTraditionalChinese": "繁体中文(推荐)",
"SettingsTabSystemSystemTimeZone": "系统时区:",
"SettingsTabSystemSystemTime": "系统时钟:",
"SettingsTabSystemEnableVsync": "开启 VSync",
"SettingsTabSystemEnablePptc": "开启 PPTC 缓存",
"SettingsTabSystemEnableFsIntegrityChecks": "开启文件系统完整性检查",
"SettingsTabSystemAudioBackend": "音频后端:",
"SettingsTabSystemAudioBackendDummy": "无",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "修正",
"SettingsTabSystemHacksNote": " - 会引起模拟器不稳定",
"SettingsTabSystemExpandDramSize": "将模拟RAM大小扩展至 6GB",
"SettingsTabSystemIgnoreMissingServices": "忽略缺少的服务",
"SettingsTabGraphics": "图像",
"SettingsTabGraphicsEnhancements": "增强",
"SettingsTabGraphicsEnableShaderCache": "启用着色器缓存",
"SettingsTabGraphicsAnisotropicFiltering": "各向异性过滤:",
"SettingsTabGraphicsAnisotropicFilteringAuto": "自动",
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
"SettingsTabGraphicsResolutionScale": "分辨率缩放:",
"SettingsTabGraphicsResolutionScaleCustom": "自定义 (不推荐)",
"SettingsTabGraphicsResolutionScaleNative": "原生 (720p/1080p)",
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
"SettingsTabGraphicsAspectRatio": "宽高比:",
"SettingsTabGraphicsAspectRatio4x3": "4:3",
"SettingsTabGraphicsAspectRatio16x9": "16:9",
"SettingsTabGraphicsAspectRatio16x10": "16:10",
"SettingsTabGraphicsAspectRatio21x9": "21:9",
"SettingsTabGraphicsAspectRatio32x9": "32:9",
"SettingsTabGraphicsAspectRatioStretch": "拉伸至屏幕",
"SettingsTabGraphicsDeveloperOptions": "开发者选项",
"SettingsTabGraphicsShaderDumpPath": "图形着色器转储路径:",
"SettingsTabLogging": "日志",
"SettingsTabLoggingLogging": "日志",
"SettingsTabLoggingEnableLoggingToFile": "保存日志为文件",
"SettingsTabLoggingEnableStubLogs": "记录Stub",
"SettingsTabLoggingEnableInfoLogs": "记录Info",
"SettingsTabLoggingEnableWarningLogs": "记录Warning",
"SettingsTabLoggingEnableErrorLogs": "记录Error",
"SettingsTabLoggingEnableTraceLogs": "记录Trace",
"SettingsTabLoggingEnableGuestLogs": "记录Guest",
"SettingsTabLoggingEnableFsAccessLogs": "记录文件访问",
"SettingsTabLoggingFsGlobalAccessLogMode": "记录全局文件访问模式:",
"SettingsTabLoggingDeveloperOptions": "开发者选项 (警告: 会降低性能)",
"SettingsTabLoggingOpenglLogLevel": "OpenGL日志级别:",
"SettingsTabLoggingOpenglLogLevelNone": "无",
"SettingsTabLoggingOpenglLogLevelError": "错误",
"SettingsTabLoggingOpenglLogLevelPerformance": "减速",
"SettingsTabLoggingOpenglLogLevelAll": "全部",
"SettingsTabLoggingEnableDebugLogs": "启用调试日志",
"SettingsTabInput": "输入",
"SettingsTabInputEnableDockedMode": "主机模式",
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
"SettingsButtonSave": "保存",
"SettingsButtonClose": "关闭",
"SettingsButtonApply": "应用",
"ControllerSettingsPlayer": "玩家",
"ControllerSettingsPlayer1": "玩家 1",
"ControllerSettingsPlayer2": "玩家 2",
"ControllerSettingsPlayer3": "玩家 3",
"ControllerSettingsPlayer4": "玩家 4",
"ControllerSettingsPlayer5": "玩家 5",
"ControllerSettingsPlayer6": "玩家 6",
"ControllerSettingsPlayer7": "玩家 7",
"ControllerSettingsPlayer8": "玩家 8",
"ControllerSettingsHandheld": "掌机模式",
"ControllerSettingsInputDevice": "输入设备",
"ControllerSettingsRefresh": "刷新",
"ControllerSettingsDeviceDisabled": "关闭",
"ControllerSettingsControllerType": "手柄类型",
"ControllerSettingsControllerTypeHandheld": "掌机",
"ControllerSettingsControllerTypeProController": "Pro手柄",
"ControllerSettingsControllerTypeJoyConPair": "JoyCon",
"ControllerSettingsControllerTypeJoyConLeft": "左JoyCon",
"ControllerSettingsControllerTypeJoyConRight": "右JoyCon",
"ControllerSettingsProfile": "预设",
"ControllerSettingsProfileDefault": "默认",
"ControllerSettingsLoad": "加载",
"ControllerSettingsAdd": "新建",
"ControllerSettingsRemove": "删除",
"ControllerSettingsButtons": "按钮",
"ControllerSettingsButtonA": "A",
"ControllerSettingsButtonB": "B",
"ControllerSettingsButtonX": "X",
"ControllerSettingsButtonY": "Y",
"ControllerSettingsButtonPlus": "+",
"ControllerSettingsButtonMinus": "-",
"ControllerSettingsDPad": "方向键",
"ControllerSettingsDPadUp": "上",
"ControllerSettingsDPadDown": "下",
"ControllerSettingsDPadLeft": "左",
"ControllerSettingsDPadRight": "右",
"ControllerSettingsLStick": "左摇杆",
"ControllerSettingsLStickButton": "按下",
"ControllerSettingsLStickUp": "上",
"ControllerSettingsLStickDown": "下",
"ControllerSettingsLStickLeft": "左",
"ControllerSettingsLStickRight": "右",
"ControllerSettingsLStickStick": "杆",
"ControllerSettingsLStickInvertXAxis": "反转 X 方向",
"ControllerSettingsLStickInvertYAxis": "反转 Y 方向",
"ControllerSettingsLStickDeadzone": "死区:",
"ControllerSettingsRStick": "右摇杆",
"ControllerSettingsRStickButton": "按下",
"ControllerSettingsRStickUp": "上",
"ControllerSettingsRStickDown": "下",
"ControllerSettingsRStickLeft": "左",
"ControllerSettingsRStickRight": "右",
"ControllerSettingsRStickStick": "杆",
"ControllerSettingsRStickInvertXAxis": "反转 X 方向",
"ControllerSettingsRStickInvertYAxis": "反转 Y 方向",
"ControllerSettingsRStickDeadzone": "死区:",
"ControllerSettingsTriggersLeft": "左扳机",
"ControllerSettingsTriggersRight": "右扳机",
"ControllerSettingsTriggersButtonsLeft": "左扳机键",
"ControllerSettingsTriggersButtonsRight": "右扳机键",
"ControllerSettingsTriggers": "扳机",
"ControllerSettingsTriggerL": "L",
"ControllerSettingsTriggerR": "R",
"ControllerSettingsTriggerZL": "ZL",
"ControllerSettingsTriggerZR": "ZR",
"ControllerSettingsLeftSL": "SL",
"ControllerSettingsLeftSR": "SR",
"ControllerSettingsRightSL": "SL",
"ControllerSettingsRightSR": "SR",
"ControllerSettingsExtraButtonsLeft": "左按键",
"ControllerSettingsExtraButtonsRight": "右按键",
"ControllerSettingsMisc": "其他",
"ControllerSettingsTriggerThreshold": "扳机阈值:",
"ControllerSettingsMotion": "体感",
"ControllerSettingsCemuHook": "CemuHook",
"ControllerSettingsMotionEnableMotionControls": "启用体感操作",
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "使用CemuHook体感协议",
"ControllerSettingsMotionControllerSlot": "手柄:",
"ControllerSettingsMotionMirrorInput": "镜像操作",
"ControllerSettingsMotionRightJoyConSlot": "右JoyCon:",
"ControllerSettingsMotionServerHost": "服务器Host:",
"ControllerSettingsMotionGyroSensitivity": "陀螺仪敏感度:",
"ControllerSettingsMotionGyroDeadzone": "陀螺仪死区:",
"ControllerSettingsSave": "保存",
"ControllerSettingsClose": "关闭",
"UserProfilesSelectedUserProfile": "选择用户账户:",
"UserProfilesSaveProfileName": "保存账户名",
"UserProfilesChangeProfileImage": "更换头像",
"UserProfilesAvailableUserProfiles": "现有的账户:",
"UserProfilesAddNewProfile": "新建账户",
"UserProfilesDeleteSelectedProfile": "删除选择的账户",
"UserProfilesClose": "关闭",
"ProfileImageSelectionTitle": "头像选择",
"ProfileImageSelectionHeader": "选择合适的头像图片",
"ProfileImageSelectionNote": "您可以导入自定义头像,或从系统中选择头像",
"ProfileImageSelectionImportImage": "导入图像文件",
"ProfileImageSelectionSelectAvatar": "选择系统头像",
"InputDialogTitle": "输入对话框",
"InputDialogOk": "完成",
"InputDialogCancel": "取消",
"InputDialogAddNewProfileTitle": "选择用户名称",
"InputDialogAddNewProfileHeader": "请输入账户名称",
"InputDialogAddNewProfileSubtext": "(最大长度: {0})",
"AvatarChoose": "选择",
"AvatarSetBackgroundColor": "设置背景色",
"AvatarClose": "关闭",
"ControllerSettingsLoadProfileToolTip": "加载预设",
"ControllerSettingsAddProfileToolTip": "新增预设",
"ControllerSettingsRemoveProfileToolTip": "删除预设",
"ControllerSettingsSaveProfileToolTip": "保存预设",
"MenuBarFileToolsTakeScreenshot": "保存截图",
"MenuBarFileToolsHideUi": "隐藏UI",
"GameListContextMenuToggleFavorite": "标记为收藏",
"GameListContextMenuToggleFavoriteToolTip": "启用或取消收藏标记",
"SettingsTabGeneralTheme": "主题",
"SettingsTabGeneralThemeCustomTheme": "自选主题路径",
"SettingsTabGeneralThemeBaseStyle": "主题色调",
"SettingsTabGeneralThemeBaseStyleDark": "暗黑",
"SettingsTabGeneralThemeBaseStyleLight": "浅色",
"SettingsTabGeneralThemeEnableCustomTheme": "使用自选主题界面",
"ButtonBrowse": "浏览",
"ControllerSettingsMotionConfigureCemuHookSettings": "配置CemuHook体感",
"ControllerSettingsRumble": "震动",
"ControllerSettingsRumbleEnable": "启用震动",
"ControllerSettingsRumbleStrongMultiplier": "强震动调节",
"ControllerSettingsRumbleWeakMultiplier": "弱震动调节",
"DialogMessageSaveNotAvailableMessage": "没有{0} [{1:x16}]的游戏存档",
"DialogMessageSaveNotAvailableCreateSaveMessage": "是否创建该游戏的存档文件夹?",
"DialogConfirmationTitle": "Ryujinx - 设置",
"DialogUpdaterTitle": "Ryujinx - 更新",
"DialogErrorTitle": "Ryujinx - 错误",
"DialogWarningTitle": "Ryujinx - 警告",
"DialogExitTitle": "Ryujinx - 关闭",
"DialogErrorMessage": "Ryujinx遇到了错误",
"DialogExitMessage": "是否关闭Ryujinx",
"DialogExitSubMessage": "所有未保存的进度会丢失!",
"DialogMessageCreateSaveErrorMessage": "创建特定的存档时出错: {0}",
"DialogMessageFindSaveErrorMessage": "查找特定的存档时出错: {0}",
"FolderDialogExtractTitle": "选择要解压到的文件夹",
"DialogNcaExtractionMessage": "提取{1}的{0}分区...",
"DialogNcaExtractionTitle": "Ryujinx - NCA分区提取",
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "提取失败。所选文件中不含主NCA文件",
"DialogNcaExtractionCheckLogErrorMessage": "提取失败。请查看日志文件获取详情。",
"DialogNcaExtractionSuccessMessage": "提取成功。",
"DialogUpdaterConvertFailedMessage": "无法转换当前 Ryujinx 版本。",
"DialogUpdaterCancelUpdateMessage": "更新取消!",
"DialogUpdaterAlreadyOnLatestVersionMessage": "您使用的Ryujinx是最新版本。",
"DialogUpdaterFailedToGetVersionMessage": "尝试从 Github 获取版本信息时无效。可能由于 GitHub Actions 正在编译新版本。请过几分钟重试。",
"DialogUpdaterConvertFailedGithubMessage": "无法转换从 Github 接收到的 Ryujinx 版本转换。",
"DialogUpdaterDownloadingMessage": "下载新版本中...",
"DialogUpdaterExtractionMessage": "正在提取更新...",
"DialogUpdaterRenamingMessage": "正在删除旧文件...",
"DialogUpdaterAddingFilesMessage": "安装更新中...",
"DialogUpdaterCompleteMessage": "更新成功!",
"DialogUpdaterRestartMessage": "立即重启 Ryujinx 完成更新?",
"DialogUpdaterArchNotSupportedMessage": "您运行的系统架构不受支持!",
"DialogUpdaterArchNotSupportedSubMessage": "(仅支持 x64 系统)",
"DialogUpdaterNoInternetMessage": "没有连接到互联网",
"DialogUpdaterNoInternetSubMessage": "请确保互联网连接正常。",
"DialogUpdaterDirtyBuildMessage": "不能更新第三方版本的 Ryujinx",
"DialogUpdaterDirtyBuildSubMessage": "如果希望使用受支持的版本,请您在 https://ryujinx.org/ 下载。",
"DialogRestartRequiredMessage": "需要重启模拟器",
"DialogThemeRestartMessage": "主题设置已保存。需要重新启动才能生效。",
"DialogThemeRestartSubMessage": "您是否要重启?",
"DialogFirmwareInstallEmbeddedMessage": "要安装游戏内置的固件吗?(固件 {0})",
"DialogFirmwareInstallEmbeddedSuccessMessage": "未找到已安装的固件,但 Ryujinx 可以从现有的游戏安装固件{0}.\\n模拟器现在可以运行。",
"DialogFirmwareNoFirmwareInstalledMessage": "未安装固件",
"DialogFirmwareInstalledMessage": "已安装固件{0}",
"DialogOpenSettingsWindowLabel": "打开设置窗口",
"DialogControllerAppletTitle": "控制器小窗口",
"DialogMessageDialogErrorExceptionMessage": "显示消息对话框时出错: {0}",
"DialogSoftwareKeyboardErrorExceptionMessage": "显示软件键盘时出错: {0}",
"DialogErrorAppletErrorExceptionMessage": "显示错误对话框时出错: {0}",
"DialogUserErrorDialogMessage": "{0}: {1}",
"DialogUserErrorDialogInfoMessage": "\n有关修复此错误的更多信息可以遵循我们的设置指南。",
"DialogUserErrorDialogTitle": "Ryujinx错误 ({0})",
"DialogAmiiboApiTitle": "Amiibo API",
"DialogAmiiboApiFailFetchMessage": "从 API 获取信息时出错。",
"DialogAmiiboApiConnectErrorMessage": "无法连接到 Amiibo API 服务器。服务器可能已关闭,或者您没有网络连接。",
"DialogProfileInvalidProfileErrorMessage": "预设{0} 与当前输入配置系统不兼容。",
"DialogProfileDefaultProfileOverwriteErrorMessage": "默认预设无法被覆盖",
"DialogProfileDeleteProfileTitle": "删除预设",
"DialogProfileDeleteProfileMessage": "删除后不可恢复,确定吗?",
"DialogWarning": "警告",
"DialogPPTCDeletionMessage": "您即将删除:\n\n{0}的 PPTC 缓存\n\n确定吗",
"DialogPPTCDeletionErrorMessage": "清除位于{0}的 PPTC 缓存时出错: {1}",
"DialogShaderDeletionMessage": "您即将删除:\n\n{0}的着色器缓存\n\n确定吗",
"DialogShaderDeletionErrorMessage": "清除位于{0}的着色器缓存时出错: {1}",
"DialogRyujinxErrorMessage": "Ryujinx遇到错误",
"DialogInvalidTitleIdErrorMessage": "UI 错误:所选游戏没有有效的标题ID",
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "路径{0}找不到有效的系统固件。",
"DialogFirmwareInstallerFirmwareInstallTitle": "安装固件{0}",
"DialogFirmwareInstallerFirmwareInstallMessage": "将安装{0}版本的系统。",
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n这将替换当前系统版本{0}。",
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n确认进行?",
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "安装固件中...",
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "成功安装系统版本{0}。",
"DialogUserProfileDeletionWarningMessage": "删除后将没有可选择的用户账户",
"DialogUserProfileDeletionConfirmMessage": "是否删除选择的账户",
"DialogControllerSettingsModifiedConfirmMessage": "目前的输入预设已更新",
"DialogControllerSettingsModifiedConfirmSubMessage": "要保存吗?",
"DialogDlcLoadNcaErrorMessage": "{0}. 错误的文件: {1}",
"DialogDlcNoDlcErrorMessage": "选择的文件不包含所选游戏的 DLC",
"DialogPerformanceCheckLoggingEnabledMessage": "您启用了跟踪日志,仅供开发人员使用。",
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "为了获得最佳性能,建议禁用跟踪日志记录。您是否要立即禁用?",
"DialogPerformanceCheckShaderDumpEnabledMessage": "您启用了着色器转储,仅供开发人员使用。",
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "为了获得最佳性能,建议禁用着色器转储。您是否要立即禁用?",
"DialogLoadAppGameAlreadyLoadedMessage": "当前已加载有游戏",
"DialogLoadAppGameAlreadyLoadedSubMessage": "请停止模拟或关闭程序,再启动另一个游戏。",
"DialogUpdateAddUpdateErrorMessage": "选择的文件不包含所选游戏的更新!",
"DialogSettingsBackendThreadingWarningTitle": "警告 - 后端多线程",
"DialogSettingsBackendThreadingWarningMessage": "改变此选项后必须重启 Ryujinx 才能生效。根据您的硬件您开启该选项时可能需要手动禁用驱动程序本身的GL多线程。",
"SettingsTabGraphicsFeaturesOptions": "功能",
"SettingsTabGraphicsBackendMultithreading": "后端多线程:",
"CommonAuto": "自动(推荐)",
"CommonOff": "关闭",
"CommonOn": "打开",
"InputDialogYes": "是",
"InputDialogNo": "否",
"DialogProfileInvalidProfileNameErrorMessage": "文件名包含无效字符,请重试。",
"MenuBarOptionsPauseEmulation": "暂停",
"MenuBarOptionsResumeEmulation": "继续",
"AboutUrlTooltipMessage": "在浏览器中打开Ryujinx的官网。",
"AboutDisclaimerMessage": "Ryujinx以任何方式都与Nintendo™以及任何商业伙伴没有关联",
"AboutAmiiboDisclaimerMessage": "我们的Amiibo模拟使用了\nAmiiboAPI (www.amiiboapi.com) ",
"AboutPatreonUrlTooltipMessage": "在浏览器中打开Ryujinx的Patreon赞助页。",
"AboutGithubUrlTooltipMessage": "在浏览器中打开Ryujinx的GitHub代码库。",
"AboutDiscordUrlTooltipMessage": "在浏览器中打开Ryujinx的Discord邀请链接。",
"AboutTwitterUrlTooltipMessage": "在浏览器中打开Ryujinx的Twitter主页。",
"AboutRyujinxAboutTitle": "关于:",
"AboutRyujinxAboutContent": "Ryujinx是Nintendo Switch™的模拟器.\n您可以在Patreon上支持Ryujinx。\n关注Twitter或者Discord可以获取模拟器最新动态。\n如果您对开发感兴趣欢迎来GitHub和Discord加入我们",
"AboutRyujinxMaintainersTitle": "由以下作者维护:",
"AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者的网页",
"AboutRyujinxSupprtersTitle": "感谢Patreon的赞助者:",
"AmiiboSeriesLabel": "Amiibo系列",
"AmiiboCharacterLabel": "角色",
"AmiiboScanButtonLabel": "扫描",
"AmiiboOptionsShowAllLabel": "显示所有 Amiibo",
"AmiiboOptionsUsRandomTagLabel": "修正: 使用随机标记的Uuid",
"DlcManagerTableHeadingEnabledLabel": "启用",
"DlcManagerTableHeadingTitleIdLabel": "游戏ID",
"DlcManagerTableHeadingContainerPathLabel": "文件夹路径",
"DlcManagerTableHeadingFullPathLabel": "完整路径",
"DlcManagerRemoveAllButton": "全部删除",
"MenuBarOptionsChangeLanguage": "更改语言",
"CommonSort": "排序",
"CommonShowNames": "显示名称",
"CommonFavorite": "收藏",
"OrderAscending": "从小到大",
"OrderDescending": "从大到小",
"SettingsTabGraphicsFeatures": "额外功能",
"ErrorWindowTitle": "错误窗口",
"ToggleDiscordTooltip": "启用或关闭Discord详细在线状态展示",
"AddGameDirBoxTooltip": "输入要添加的游戏目录",
"AddGameDirTooltip": "添加游戏目录到列表中",
"RemoveGameDirTooltip": "移除选中的目录",
"CustomThemeCheckTooltip": "启用或关闭自定义主题",
"CustomThemePathTooltip": "自定义主题的目录",
"CustomThemeBrowseTooltip": "查找自定义主题",
"DockModeToggleTooltip": "是否开启Swith的主机模式",
"DirectKeyboardTooltip": "是否开启\"直连键盘访问(HID)支持\" (部分游戏可以使用您的键盘输入文字)",
"DirectMouseTooltip": "是否开启\"直连鼠标访问(HID)支持\" (部分游戏可以使用您的鼠标导航)",
"RegionTooltip": "更改系统区域",
"LanguageTooltip": "更改系统语言",
"TimezoneTooltip": "更改系统时区",
"TimeTooltip": "更改系统时钟",
"VSyncToggleTooltip": "开启可以消除帧撕裂,关闭可以提高性能",
"PptcToggleTooltip": "开启以后减少游戏启动时间",
"FsIntegrityToggleTooltip": "是否检查游戏文件内容的完整性",
"AudioBackendTooltip": "默认推荐SDL但每种音频后端对各类游戏兼容性可能不同",
"MemoryManagerTooltip": "改变Switch内存映射到电脑内存的方式会影响CPU性能消耗",
"MemoryManagerSoftwareTooltip": "使用软件内存页管理,最精确但是速度最慢",
"MemoryManagerHostTooltip": "直接映射内存页到电脑内存JIT效率很高",
"MemoryManagerUnsafeTooltip": "直接映射内存页但是不检查内存溢出JIT效率最高。Ryujinx可以访问任何位置的内存所以相对不安全。此模式下只应运行您信任的游戏或软件即官方游戏",
"DRamTooltip": "扩展模拟的Switch内存为6GB某些高清纹理MOD或4K MOD需要此选项",
"IgnoreMissingServicesTooltip": "忽略某些未实现的系统服务,少部分游戏需要此选项才能启动",
"GraphicsBackendThreadingTooltip": "启用后端多线程",
"GalThreadingTooltip": "使用模拟器自带的多线程调度,减少着色器编译的卡顿,并提高驱动程序的性能(尤其是缺失多线程的AMD)。NVIDIA用户需要重启模拟器才能禁用驱动本身的多线程否则您需手动执行禁用获得最佳性能",
"ShaderCacheToggleTooltip": "开启后缓存着色器到硬盘,减少画面卡顿",
"ResolutionScaleTooltip": "缩放渲染的分辨率",
"ResolutionScaleEntryTooltip": "尽量使用如1.5的浮点倍数。非整数的倍率易引起错误",
"AnisotropyTooltip": "各向异性过滤等级。能提高倾斜视角纹理的清晰度('自动'使用游戏默认指定的等级)",
"AspectRatioTooltip": "模拟器渲染窗口的宽高比",
"ShaderDumpPathTooltip": "转储图形着色器的路径",
"FileLogTooltip": "是否保存日志文件到硬盘",
"StubLogTooltip": "记录stub消息",
"InfoLogTooltip": "记录info消息",
"WarnLogTooltip": "记录warning消息",
"ErrorLogTooltip": "记录error消息",
"TraceLogTooltip": "记录trace消息",
"GuestLogTooltip": "记录guest消息",
"FileAccessLogTooltip": "记录文件访问消息",
"FSAccessLogModeTooltip": "记录FS访问消息输出到控制台。可选的模式是0-3",
"DeveloperOptionTooltip": "使用请谨慎",
"OpenGlLogLevel": "需要打开适当的日志等级",
"DebugLogTooltip": "记录debug消息",
"LoadApplicationFileTooltip": "选择Switch格式的游戏并加载",
"LoadApplicationFolderTooltip": "选择一个解包后格式的Switch游戏并加载",
"OpenRyujinxFolderTooltip": "打开Ryujinx系统目录",
"OpenRyujinxLogsTooltip": "打开日志存放的目录",
"ExitTooltip": "关闭Ryujinx",
"OpenSettingsTooltip": "打开设置窗口",
"OpenProfileManagerTooltip": "打开用户账号管理器",
"StopEmulationTooltip": "停止运行当前游戏并回到选择界面",
"CheckUpdatesTooltip": "检查新版本Ryujinx",
"OpenAboutTooltip": "打开'关于'窗口",
"GridSize": "网格尺寸",
"GridSizeTooltip": "调整网格模式的大小",
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "巴西葡萄牙语",
"AboutRyujinxContributorsButtonHeader": "查看所有参与者",
"SettingsTabSystemAudioVolume": "音量: ",
"AudioVolumeTooltip": "调节音量",
"SettingsTabSystemEnableInternetAccess": "启用网络连接",
"EnableInternetAccessTooltip": "开启互联网访问。此选项打开后效果类似于Switch连接到互联网的状态。注意即使此选项关闭应用程序也偶尔有可能连接到网络",
"GameListContextMenuManageCheatToolTip": "管理金手指",
"GameListContextMenuManageCheat": "管理金手指",
"ControllerSettingsStickRange": "范围",
"DialogStopEmulationTitle": "Ryujinx - 停止模拟",
"DialogStopEmulationMessage": "是否确定停止模拟?",
"SettingsTabCpu": "CPU",
"SettingsTabAudio": "音频",
"SettingsTabNetwork": "网络",
"SettingsTabNetworkConnection": "网络连接",
"[REMOVE]SettingsTabGraphicsFrameRate": "主机刷新率:",
"[REMOVE]SettingsTabGraphicsFrameRateTooltip": "设置主机刷新率。设为 0 可以取消帧率限制",
"SettingsTabCpuCache": "CPU 缓存",
"SettingsTabCpuMemory": "CPU 内存",
"DialogUpdaterFlatpakNotSupportedMessage": "请通过 FlatHub 更新 Ryujinx。",
"UpdaterDisabledWarningTitle": "更新已禁用!",
"GameListContextMenuOpenSdModsDirectory": "打开Atmosphere MOD目录",
"GameListContextMenuOpenSdModsDirectoryToolTip": "打开包含应用程序MOD的其他Atmosphere SD卡目录",
"ControllerSettingsRotate90": "顺时针旋转 90°",
"IconSize": "图标尺寸",
"IconSizeTooltip": "更改游戏图标大小",
"MenuBarOptionsShowConsole": "显示控制台",
"ShaderCachePurgeError": "清除着色器缓存时出错: {0}: {1}",
"UserErrorNoKeys": "找不到密钥",
"UserErrorNoFirmware": "找不到固件",
"UserErrorFirmwareParsingFailed": "固件解析错误",
"UserErrorApplicationNotFound": "找不到应用程序",
"UserErrorUnknown": "未知错误",
"UserErrorUndefined": "未定义错误",
"UserErrorNoKeysDescription": "Ryujinx找不到 'prod.keys' 文件",
"UserErrorNoFirmwareDescription": "Ryujinx找不到任何已安装的固件",
"UserErrorFirmwareParsingFailedDescription": "Ryujinx无法解密选择的固件。通常是由于过旧的密钥。",
"UserErrorApplicationNotFoundDescription": "Ryujinx在选中路径找不到有效的应用程序。",
"UserErrorUnknownDescription": "发生未知错误!",
"UserErrorUndefinedDescription": "发生了未定义错误!此类错误不应出现,请联系开发人员!",
"OpenSetupGuideMessage": "打开设置教程",
"NoUpdate": "没有新版",
"TitleUpdateVersionLabel": "版本 {0} - {1}",
"RyujinxInfo": "Ryujinx - 信息",
"RyujinxConfirm": "Ryujinx - 确认",
"FileDialogAllTypes": "全部类型",
"Never": "从不",
"SwkbdMinCharacters": "至少应为 {0} 个字长",
"SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字长",
"SoftwareKeyboard": "软件键盘",
"DialogControllerAppletMessagePlayerRange": "游戏需要 {0} 个玩家()持有:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}请打开设置界面,配置手柄;或者关闭窗口。",
"DialogControllerAppletMessage": "游戏需要刚好 {0} 个玩家()持有 with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}请打开设置界面,配置手柄;或者关闭窗口。",
"DialogControllerAppletDockModeSet": "现在处于主机模式,无法使用掌机操作方式\n\n",
"UpdaterRenaming": "正在删除旧文件...",
"UpdaterRenameFailed": "更新过程中无法重命名文件: {0}",
"UpdaterAddingFiles": "安装更新中...",
"UpdaterExtracting": "正在提取更新...",
"UpdaterDownloading": "下载新版本中...",
"Game": "游戏",
"Docked": "主机模式",
"Handheld": "掌机模式",
"ConnectionError": "连接错误。",
"AboutPageDeveloperListMore": "{0} 以及等人...",
"ApiError": "API错误。",
"LoadingHeading": "正在加载 {0}",
"CompilingPPTC": "编译PPTC中",
"CompilingShaders": "编译着色器中",
"AllKeyboards": "所有键盘",
"OpenFileDialogTitle": "选择支持的文件格式",
"OpenFolderDialogTitle": "选择一个包含解包游戏的文件夹",
"AllSupportedFormats": "全部支持的格式",
"RyujinxUpdater": "Ryujinx 更新程序"
}

View File

@@ -1,9 +1,7 @@
<Styles <Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" /> <StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20" Height="2000"> <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">
@@ -27,8 +25,12 @@
Name="btnRem" Name="btnRem"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Content="Add" /> Content="Add" />
<TextBox Width="100" VerticalAlignment="Center" Text="Rrrrr" Watermark="Hello" <TextBox
UseFloatingWatermark="True" /> Width="100"
VerticalAlignment="Center"
Text="Rrrrr"
UseFloatingWatermark="True"
Watermark="Hello" />
<CheckBox>Test Check</CheckBox> <CheckBox>Test Check</CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -1,9 +1,7 @@
<Styles <Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" /> <StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20" Height="2000"> <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">
@@ -27,8 +25,12 @@
Name="btnRem" Name="btnRem"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Content="Add" /> Content="Add" />
<TextBox Width="100" VerticalAlignment="Center" Text="Rrrrr" Watermark="Hello" <TextBox
UseFloatingWatermark="True" /> Width="100"
VerticalAlignment="Center"
Text="Rrrrr"
UseFloatingWatermark="True"
Watermark="Hello" />
<CheckBox>Test Check</CheckBox> <CheckBox>Test Check</CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -1,10 +1,10 @@
<Styles <Styles
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:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:sys="clr-namespace:System;assembly=netstandard"> xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20" Height="2000"> <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">
@@ -22,15 +22,19 @@
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<ToggleButton <ToggleButton
Name="btnAdd" Name="btnAdd"
HorizontalAlignment="Right"
Height="28" Height="28"
HorizontalAlignment="Right"
Content="Addy" /> Content="Addy" />
<Button <Button
Name="btnRem" Name="btnRem"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Content="Add" /> Content="Add" />
<TextBox Width="100" VerticalAlignment="Center" Text="Rrrrr" Watermark="Hello" <TextBox
UseFloatingWatermark="True" /> Width="100"
VerticalAlignment="Center"
Text="Rrrrr"
UseFloatingWatermark="True"
Watermark="Hello" />
<CheckBox>Test Check</CheckBox> <CheckBox>Test Check</CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>
@@ -62,13 +66,10 @@
<Style Selector="Image.huge"> <Style Selector="Image.huge">
<Setter Property="Width" Value="120" /> <Setter Property="Width" Value="120" />
</Style> </Style>
<Style Selector="RadioButton"> <Style Selector="#TitleBarHost &gt; Image">
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style Selector="#TitleBarHost > Image">
<Setter Property="Margin" Value="10" /> <Setter Property="Margin" Value="10" />
</Style> </Style>
<Style Selector="#TitleBarHost > Label"> <Style Selector="#TitleBarHost &gt; Label">
<Setter Property="Margin" Value="5" /> <Setter Property="Margin" Value="5" />
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="14" />
</Style> </Style>
@@ -225,12 +226,12 @@
<StaticResource x:Key="ListViewItemBackgroundPointerOver" ResourceKey="SystemAccentColorDark2" /> <StaticResource x:Key="ListViewItemBackgroundPointerOver" ResourceKey="SystemAccentColorDark2" />
<StaticResource x:Key="ListViewItemBackgroundSelectedPressed" ResourceKey="ThemeAccentColorBrush" /> <StaticResource x:Key="ListViewItemBackgroundSelectedPressed" ResourceKey="ThemeAccentColorBrush" />
<StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver" ResourceKey="SystemAccentColorDark2" /> <StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver" ResourceKey="SystemAccentColorDark2" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" <SolidColorBrush
Color="{DynamicResource SystemBaseMediumLowColor}" x:Key="DataGridGridLinesBrush"
Opacity="0.4" /> Opacity="0.4"
Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" /> <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
<SolidColorBrush x:Key="MenuFlyoutPresenterBorderBrush" <SolidColorBrush x:Key="MenuFlyoutPresenterBorderBrush" Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" /> <SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="ListBoxBackground" Color="{DynamicResource ThemeContentBackgroundColor}" /> <SolidColorBrush x:Key="ListBoxBackground" Color="{DynamicResource ThemeContentBackgroundColor}" />
<SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource ThemeForegroundColor}" /> <SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource ThemeForegroundColor}" />
@@ -241,7 +242,6 @@
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled" Color="#00E81123" /> <SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled" 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="TextMargin">0 4 0 0</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="MenuFlyoutPresenterBorderColor">#00000000</Color>
<Color x:Key="SystemAccentColor">#FF00C3E3</Color> <Color x:Key="SystemAccentColor">#FF00C3E3</Color>

View File

@@ -123,6 +123,7 @@
<None Remove="Assets\Locales\pt_BR.json" /> <None Remove="Assets\Locales\pt_BR.json" />
<None Remove="Assets\Locales\ru_RU.json" /> <None Remove="Assets\Locales\ru_RU.json" />
<None Remove="Assets\Locales\tr_TR.json" /> <None Remove="Assets\Locales\tr_TR.json" />
<None Remove="Assets\Locales\zh_CN.json" />
<None Remove="Assets\Styles\Styles.xaml" /> <None Remove="Assets\Styles\Styles.xaml" />
<None Remove="Assets\Styles\BaseDark.xaml" /> <None Remove="Assets\Styles\BaseDark.xaml" />
<None Remove="Assets\Styles\BaseLight.xaml" /> <None Remove="Assets\Styles\BaseLight.xaml" />
@@ -139,6 +140,7 @@
<EmbeddedResource Include="Assets\Locales\pt_BR.json" /> <EmbeddedResource Include="Assets\Locales\pt_BR.json" />
<EmbeddedResource Include="Assets\Locales\ru_RU.json" /> <EmbeddedResource Include="Assets\Locales\ru_RU.json" />
<EmbeddedResource Include="Assets\Locales\tr_TR.json" /> <EmbeddedResource Include="Assets\Locales\tr_TR.json" />
<EmbeddedResource Include="Assets\Locales\zh_CN.json" />
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,17 +1,21 @@
<Window xmlns="https://github.com/avaloniaui" <Window
x:Class="Ryujinx.Ava.Ui.Applet.ErrorAppletWindow"
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:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
mc:Ignorable="d" Title="{locale:Locale ErrorWindowTitle}"
x:Class="Ryujinx.Ava.Ui.Applet.ErrorAppletWindow"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
CanResize="False"
SizeToContent="Height"
Width="450" Width="450"
Height="340" Height="340"
Title="{locale:Locale ErrorWindowTitle}"> CanResize="False"
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="20"> SizeToContent="Height"
mc:Ignorable="d">
<Grid
Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -21,11 +25,28 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Grid.Row="1" Grid.RowSpan="2" Margin="5, 10, 20 , 10" Grid.Column="0" <Image
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" Height="80" MinWidth="50" /> Grid.Row="1"
<TextBlock Grid.Row="1" Margin="10" Grid.Column="1" VerticalAlignment="Stretch" TextWrapping="Wrap" Grid.RowSpan="2"
Text="{Binding Message}" /> Grid.Column="0"
<StackPanel Name="ButtonStack" Margin="10" Spacing="10" Grid.Row="2" Grid.Column="1" Height="80"
HorizontalAlignment="Right" Orientation="Horizontal" /> MinWidth="50"
Margin="5,10,20,10"
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
Margin="10"
VerticalAlignment="Stretch"
Text="{Binding Message}"
TextWrapping="Wrap" />
<StackPanel
Name="ButtonStack"
Grid.Row="2"
Grid.Column="1"
Margin="10"
HorizontalAlignment="Right"
Orientation="Horizontal"
Spacing="10" />
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,12 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl
x:Class="Ryujinx.Ava.Ui.Controls.SwkbdAppletDialog"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
mc:Ignorable="d" Width="400"
x:Class="Ryujinx.Ava.Ui.Controls.SwkbdAppletDialog" mc:Ignorable="d">
Width="400"> <Grid
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="20"> Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -18,15 +22,43 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Grid.Row="1" VerticalAlignment="Center" Grid.RowSpan="5" Margin="5, 10, 20 , 10" <Image
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" Height="80" Grid.Row="1"
MinWidth="50" /> Grid.RowSpan="5"
<TextBlock Grid.Row="1" Margin="5" Grid.Column="1" Text="{Binding MainText}" TextWrapping="Wrap" /> Height="80"
<TextBlock Grid.Row="2" Margin="5" Grid.Column="1" Text="{Binding SecondaryText}" TextWrapping="Wrap" /> MinWidth="50"
<TextBox Name="Input" KeyUp="Message_KeyUp" UseFloatingWatermark="True" TextInput="Message_TextInput" Margin="5,10,20,10"
Text="{Binding Message}" Grid.Row="2" VerticalAlignment="Center"
Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" /> Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
<TextBlock Name="Error" Margin="5" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Stretch" <TextBlock
Grid.Row="1"
Grid.Column="1"
Margin="5"
Text="{Binding MainText}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="2"
Grid.Column="1"
Margin="5"
Text="{Binding SecondaryText}"
TextWrapping="Wrap" />
<TextBox
Name="Input"
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
KeyUp="Message_KeyUp"
Text="{Binding Message}"
TextInput="Message_TextInput"
TextWrapping="Wrap"
UseFloatingWatermark="True" />
<TextBlock
Name="Error"
Grid.Row="4"
Grid.Column="1"
Margin="5"
HorizontalAlignment="Stretch"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,13 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl
x:Class="Ryujinx.Ava.Ui.Controls.GameGridView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Ui.Controls.GameGridView"> d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" /> <controls:BitmapArrayValueConverter x:Key="ByteImage" />
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened"> <MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
@@ -88,18 +91,22 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListBox Grid.Row="0" <ListBox
Grid.Row="0"
Padding="8" Padding="8"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
DoubleTapped="GameList_DoubleTapped"
SelectionChanged="GameList_SelectionChanged"
ContextFlyout="{StaticResource GameContextMenu}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Items="{Binding AppsObservableList}"> ContextFlyout="{StaticResource GameContextMenu}"
DoubleTapped="GameList_DoubleTapped"
Items="{Binding AppsObservableList}"
SelectionChanged="GameList_SelectionChanged">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<flex:FlexPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" JustifyContent="Center" <flex:FlexPanel
AlignContent="FlexStart" /> HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AlignContent="FlexStart"
JustifyContent="Center" />
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.Styles> <ListBox.Styles>
@@ -144,42 +151,66 @@
</Style> </Style>
</Grid.Styles> </Grid.Styles>
<Border <Border
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}" Margin="0"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}" Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}" CornerRadius="5" VerticalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="0" ClipToBounds="True"> Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
ClipToBounds="True"
CornerRadius="5">
<Grid Margin="0"> <Grid Margin="0">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="0" Grid.Row="0" <Image
Grid.Row="0"
Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<StackPanel IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}" <StackPanel
Height="50" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1"
Margin="5" Grid.Row="1"> Height="50"
<TextBlock Text="{Binding TitleName}" TextAlignment="Center" TextWrapping="Wrap" Margin="5"
HorizontalAlignment="Stretch" /> HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding TitleName}"
TextAlignment="Center"
TextWrapping="Wrap" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border> </Border>
<ui:SymbolIcon Classes.icon="true" Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}" <ui:SymbolIcon
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}" Margin="5"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}" HorizontalAlignment="Left"
VerticalAlignment="Top"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Foreground="Yellow" Symbol="StarFilled" Classes.icon="true"
IsVisible="{Binding Favorite}" Margin="5" VerticalAlignment="Top"
HorizontalAlignment="Left" />
<ui:SymbolIcon Classes.icon="true" Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}" Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Foreground="Yellow"
IsVisible="{Binding Favorite}"
Symbol="StarFilled" />
<ui:SymbolIcon
Margin="5"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Foreground="Black" Symbol="Star" Classes.icon="true"
IsVisible="{Binding Favorite}" Margin="5" VerticalAlignment="Top" Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
HorizontalAlignment="Left" /> Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Foreground="Black"
IsVisible="{Binding Favorite}"
Symbol="Star" />
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>

View File

@@ -1,13 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl
x:Class="Ryujinx.Ava.Ui.Controls.GameListView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Ui.Controls.GameListView"> d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" /> <controls:BitmapArrayValueConverter x:Key="ByteImage" />
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened"> <MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
@@ -88,18 +91,23 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListBox Grid.Row="0" <ListBox
Name="GameListBox"
Grid.Row="0"
Padding="8" Padding="8"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
DoubleTapped="GameList_DoubleTapped"
SelectionChanged="GameList_SelectionChanged"
ContextFlyout="{StaticResource GameContextMenu}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Name="GameListBox" ContextFlyout="{StaticResource GameContextMenu}"
Items="{Binding AppsObservableList}"> DoubleTapped="GameList_DoubleTapped"
Items="{Binding AppsObservableList}"
SelectionChanged="GameList_SelectionChanged">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical" Spacing="2" /> <StackPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Orientation="Vertical"
Spacing="2" />
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.Styles> <ListBox.Styles>
@@ -130,9 +138,13 @@
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid> <Grid>
<Border HorizontalAlignment="Stretch" <Border
Padding="10" CornerRadius="5" Margin="0"
VerticalAlignment="Stretch" Margin="0" ClipToBounds="True"> Padding="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ClipToBounds="True"
CornerRadius="5">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -144,40 +156,78 @@
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image <Image
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}" Grid.RowSpan="3"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}" Grid.Column="0"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}" Margin="0"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}" Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Grid.RowSpan="3" Grid.Column="0" Margin="0" Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<StackPanel Orientation="Vertical" Spacing="5" VerticalAlignment="Top" HorizontalAlignment="Left" <StackPanel
Grid.Column="2"> Grid.Column="2"
<TextBlock Text="{Binding TitleName}" TextAlignment="Left" TextWrapping="Wrap" HorizontalAlignment="Left"
HorizontalAlignment="Stretch" /> VerticalAlignment="Top"
<TextBlock Text="{Binding Developer}" TextAlignment="Left" TextWrapping="Wrap" Orientation="Vertical"
HorizontalAlignment="Stretch" /> Spacing="5">
<TextBlock Text="{Binding Version}" TextAlignment="Left" TextWrapping="Wrap" <TextBlock
HorizontalAlignment="Stretch" /> HorizontalAlignment="Stretch"
Text="{Binding TitleName}"
TextAlignment="Left"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding Developer}"
TextAlignment="Left"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding Version}"
TextAlignment="Left"
TextWrapping="Wrap" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" Spacing="5" VerticalAlignment="Top" HorizontalAlignment="Right" <StackPanel
Grid.Column="3"> Grid.Column="3"
<TextBlock Text="{Binding TimePlayed}" TextAlignment="Right" TextWrapping="Wrap" HorizontalAlignment="Right"
HorizontalAlignment="Stretch" /> VerticalAlignment="Top"
<TextBlock Text="{Binding LastPlayed}" TextAlignment="Right" TextWrapping="Wrap" Orientation="Vertical"
HorizontalAlignment="Stretch" /> Spacing="5">
<TextBlock Text="{Binding FileSize}" TextAlignment="Right" TextWrapping="Wrap" <TextBlock
HorizontalAlignment="Stretch" /> HorizontalAlignment="Stretch"
Text="{Binding TimePlayed}"
TextAlignment="Right"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding LastPlayed}"
TextAlignment="Right"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding FileSize}"
TextAlignment="Right"
TextWrapping="Wrap" />
</StackPanel> </StackPanel>
<ui:SymbolIcon Grid.Row="0" Grid.Column="0" FontSize="20" <ui:SymbolIcon
Grid.Row="0"
Grid.Column="0"
Margin="-5,-5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="20"
Foreground="Yellow" Foreground="Yellow"
Symbol="StarFilled" IsVisible="{Binding Favorite}"
IsVisible="{Binding Favorite}" Margin="-5, -5, 0, 0" VerticalAlignment="Top" Symbol="StarFilled" />
HorizontalAlignment="Left" /> <ui:SymbolIcon
<ui:SymbolIcon Grid.Row="0" Grid.Column="0" FontSize="20" Grid.Row="0"
Grid.Column="0"
Margin="-5,-5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="20"
Foreground="Black" Foreground="Black"
Symbol="Star" IsVisible="{Binding Favorite}"
IsVisible="{Binding Favorite}" Margin="-5, -5, 0, 0" VerticalAlignment="Top" Symbol="Star" />
HorizontalAlignment="Left" />
</Grid> </Grid>
</Border> </Border>
</Grid> </Grid>

View File

@@ -1,18 +1,31 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl
x:Class="Ryujinx.Ava.Ui.Controls.InputDialog"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d">
x:Class="Ryujinx.Ava.Ui.Controls.InputDialog"> <Grid
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5"> Margin="5,10,5,5"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Center" Text="{Binding Message}" /> <TextBlock HorizontalAlignment="Center" Text="{Binding Message}" />
<TextBox MaxLength="{Binding MaxLength}" Grid.Row="1" Margin="10" Width="300" HorizontalAlignment="Center" <TextBox
Grid.Row="1"
Width="300"
Margin="10"
HorizontalAlignment="Center"
MaxLength="{Binding MaxLength}"
Text="{Binding Input, Mode=TwoWay}" /> Text="{Binding Input, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Margin="5, 5, 5, 10" HorizontalAlignment="Center" Text="{Binding SubMessage}" /> <TextBlock
Grid.Row="2"
Margin="5,5,5,10"
HorizontalAlignment="Center"
Text="{Binding SubMessage}" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,14 +1,18 @@
<Window xmlns="https://github.com/avaloniaui" <Window
x:Class="Ryujinx.Ava.Ui.Controls.UpdateWaitWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
mc:Ignorable="d" Title="Ryujinx - Waiting"
x:Class="Ryujinx.Ava.Ui.Controls.UpdateWaitWindow"
WindowStartupLocation="CenterOwner"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"
Title="Ryujinx - Waiting"> WindowStartupLocation="CenterOwner"
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="20"> mc:Ignorable="d">
<Grid
Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -17,12 +21,22 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Grid.Row="1" Margin="5, 10, 20 , 10" Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" <Image
Grid.Row="1"
Height="70" Height="70"
MinWidth="50" /> MinWidth="50"
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Orientation="Vertical"> Margin="5,10,20,10"
<TextBlock Margin="5" Name="PrimaryText" /> Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
<TextBlock VerticalAlignment="Center" Name="SecondaryText" Margin="5" /> <StackPanel
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock Name="PrimaryText" Margin="5" />
<TextBlock
Name="SecondaryText"
Margin="5"
VerticalAlignment="Center" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,18 +1,26 @@
<window:StyleableWindow xmlns="https://github.com/avaloniaui" <window:StyleableWindow
x:Class="Ryujinx.Ava.Ui.Windows.AboutWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="350"
x:Class="Ryujinx.Ava.Ui.Windows.AboutWindow"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
CanResize="False" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
WindowStartupLocation="CenterOwner" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Width="850" MinHeight="550" Height="550" Title="Ryujinx - About"
SizeToContent="Width" Width="850"
Height="550"
MinWidth="500" MinWidth="500"
Title="Ryujinx - About"> MinHeight="550"
<Grid Margin="15" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> d:DesignHeight="350"
d:DesignWidth="400"
CanResize="False"
SizeToContent="Width"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
<Grid
Margin="15"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -22,7 +30,12 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid Grid.Row="1" Margin="20" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="0"> <Grid
Grid.Row="1"
Grid.Column="0"
Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -40,93 +53,168 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Margin="5, 10, 20 , 10" <Image
Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" Height="110" MinWidth="50" /> Grid.Row="0"
<TextBlock FontSize="35" TextAlignment="Center" Grid.Row="0" Grid.Column="1" Text="Ryujinx" Grid.RowSpan="3"
Margin="0,20,0,0" /> Grid.Column="0"
<TextBlock FontSize="16" TextAlignment="Center" Grid.Row="1" Grid.Column="1" Text="(REE-YOU-JINX)" Height="110"
Margin="0,0,0,0" /> MinWidth="50"
<Button Grid.Column="1" Background="Transparent" HorizontalAlignment="Center" Margin="0" Grid.Row="2" Margin="5,10,20,10"
Tag="https://www.ryujinx.org/" Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" />
Click="Button_OnClick"> <TextBlock
<TextBlock ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}" Grid.Row="0"
TextAlignment="Center" TextDecorations="Underline" Text="www.ryujinx.org" /> Grid.Column="1"
Margin="0,20,0,0"
FontSize="35"
Text="Ryujinx"
TextAlignment="Center" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,0"
FontSize="16"
Text="(REE-YOU-JINX)"
TextAlignment="Center" />
<Button
Grid.Row="2"
Grid.Column="1"
Margin="0"
HorizontalAlignment="Center"
Background="Transparent"
Click="Button_OnClick"
Tag="https://www.ryujinx.org/">
<TextBlock
Text="www.ryujinx.org"
TextAlignment="Center"
TextDecorations="Underline"
ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}" />
</Button> </Button>
</Grid> </Grid>
<TextBlock TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" <TextBlock
Text="{Binding Version}" Grid.Row="1" /> Grid.Row="1"
<TextBlock Grid.Row="2" TextAlignment="Center" HorizontalAlignment="Center" Margin="20" HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Version}"
TextAlignment="Center" />
<TextBlock
Grid.Row="2"
Margin="20"
HorizontalAlignment="Center"
MaxLines="2"
Text="{locale:Locale AboutDisclaimerMessage}" Text="{locale:Locale AboutDisclaimerMessage}"
MaxLines="2" /> TextAlignment="Center" />
<TextBlock Grid.Row="3" TextAlignment="Center" HorizontalAlignment="Center" Margin="20" <TextBlock
Text="{locale:Locale AboutAmiiboDisclaimerMessage}"
Name="AmiiboLabel" Name="AmiiboLabel"
Grid.Row="3"
Margin="20"
HorizontalAlignment="Center"
MaxLines="2"
PointerPressed="AmiiboLabel_OnPointerPressed" PointerPressed="AmiiboLabel_OnPointerPressed"
MaxLines="2" /> Text="{locale:Locale AboutAmiiboDisclaimerMessage}"
<StackPanel Spacing="10" Orientation="Horizontal" Grid.Row="4" HorizontalAlignment="Center"> TextAlignment="Center" />
<StackPanel Orientation="Vertical" <StackPanel
ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}"> Grid.Row="4"
<Button Height="65" Background="Transparent" Tag="https://www.patreon.com/ryujinx" HorizontalAlignment="Center"
Click="Button_OnClick"> Orientation="Horizontal"
Spacing="10">
<StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}">
<Button
Height="65"
Background="Transparent"
Click="Button_OnClick"
Tag="https://www.patreon.com/ryujinx">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Patreon.png?assembly=Ryujinx.Ui.Common" /> <Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Patreon.png?assembly=Ryujinx.Ui.Common" />
<TextBlock Grid.Row="1" Margin="0,5,0,0" Text="Patreon" HorizontalAlignment="Center" /> <TextBlock
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Center"
Text="Patreon" />
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" <StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}">
ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}"> <Button
<Button Height="65" Background="Transparent" Tag="https://github.com/Ryujinx/Ryujinx" Height="65"
Click="Button_OnClick"> Background="Transparent"
Click="Button_OnClick"
Tag="https://github.com/Ryujinx/Ryujinx">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_GitHub.png?assembly=Ryujinx.Ui.Common" /> <Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_GitHub.png?assembly=Ryujinx.Ui.Common" />
<TextBlock Grid.Row="1" Margin="0,5,0,0" Text="GitHub" HorizontalAlignment="Center" /> <TextBlock
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Center"
Text="GitHub" />
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" <StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}">
ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}"> <Button
<Button Height="65" Background="Transparent" Tag="https://discordapp.com/invite/N2FmfVc" Height="65"
Click="Button_OnClick"> Background="Transparent"
Click="Button_OnClick"
Tag="https://discordapp.com/invite/N2FmfVc">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Discord.png?assembly=Ryujinx.Ui.Common" /> <Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Discord.png?assembly=Ryujinx.Ui.Common" />
<TextBlock Grid.Row="1" Margin="0,5,0,0" Text="Discord" HorizontalAlignment="Center" /> <TextBlock
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Center"
Text="Discord" />
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" <StackPanel Orientation="Vertical" ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}">
ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}"> <Button
<Button Height="65" Background="Transparent" Tag="https://twitter.com/RyujinxEmu" Height="65"
Click="Button_OnClick"> Background="Transparent"
Click="Button_OnClick"
Tag="https://twitter.com/RyujinxEmu">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Twitter.png?assembly=Ryujinx.Ui.Common" /> <Image Source="resm:Ryujinx.Ui.Common.Resources.Logo_Twitter.png?assembly=Ryujinx.Ui.Common" />
<TextBlock Grid.Row="1" Margin="0,5,0,0" Text="Twitter" HorizontalAlignment="Center" /> <TextBlock
Grid.Row="1"
Margin="0,5,0,0"
HorizontalAlignment="Center"
Text="Twitter" />
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Border Grid.Row="1" Grid.Column="1" VerticalAlignment="Stretch" Margin="5" Width="2" BorderBrush="White" <Border
Grid.Row="1"
Grid.Column="1"
Width="2"
Margin="5"
VerticalAlignment="Stretch"
BorderBrush="White"
BorderThickness="1,0,0,0"> BorderThickness="1,0,0,0">
<Separator Width="0" /> <Separator Width="0" />
</Border> </Border>
<Grid Grid.Row="1" Margin="20" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="2"> <Grid
Grid.Row="1"
Grid.Column="2"
Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -136,27 +224,58 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Text="{locale:Locale AboutRyujinxAboutTitle}" FontWeight="Bold" TextDecorations="Underline" /> <TextBlock
<TextBlock LineHeight="20" Grid.Row="1" Margin="20,5,5,5" FontWeight="Bold"
Text="{locale:Locale AboutRyujinxAboutTitle}"
TextDecorations="Underline" />
<TextBlock
Grid.Row="1"
Margin="20,5,5,5"
LineHeight="20"
Text="{locale:Locale AboutRyujinxAboutContent}" /> Text="{locale:Locale AboutRyujinxAboutContent}" />
<TextBlock Grid.Row="2" Margin="0,10,0,0" Text="{locale:Locale AboutRyujinxMaintainersTitle}" <TextBlock
Grid.Row="2"
Margin="0,10,0,0"
FontWeight="Bold" FontWeight="Bold"
Text="{locale:Locale AboutRyujinxMaintainersTitle}"
TextDecorations="Underline" /> TextDecorations="Underline" />
<TextBlock LineHeight="20" Grid.Row="3" Margin="20,5,5,5" <TextBlock
Grid.Row="3"
Margin="20,5,5,5"
LineHeight="20"
Text="{Binding Developers}" /> Text="{Binding Developers}" />
<Button Background="Transparent" HorizontalAlignment="Right" Grid.Row="4" <Button
Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a" Click="Button_OnClick"> Grid.Row="4"
<TextBlock ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" HorizontalAlignment="Right"
TextAlignment="Right" TextDecorations="Underline" Background="Transparent"
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}" /> Click="Button_OnClick"
Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a">
<TextBlock
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
TextAlignment="Right"
TextDecorations="Underline"
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
</Button> </Button>
<TextBlock Grid.Row="5" Margin="0,0,0,0" Text="{locale:Locale AboutRyujinxSupprtersTitle}" <TextBlock
Grid.Row="5"
Margin="0,0,0,0"
FontWeight="Bold" FontWeight="Bold"
Text="{locale:Locale AboutRyujinxSupprtersTitle}"
TextDecorations="Underline" /> TextDecorations="Underline" />
<Border Width="460" Grid.Row="6" VerticalAlignment="Stretch" Height="200" BorderThickness="1" Margin="20,5" <Border
BorderBrush="White" Padding="5"> Grid.Row="6"
<TextBlock TextWrapping="Wrap" VerticalAlignment="Top" Name="SupportersTextBlock" Width="460"
Text="{Binding Supporters}" /> Height="200"
Margin="20,5"
Padding="5"
VerticalAlignment="Stretch"
BorderBrush="White"
BorderThickness="1">
<TextBlock
Name="SupportersTextBlock"
VerticalAlignment="Top"
Text="{Binding Supporters}"
TextWrapping="Wrap" />
</Border> </Border>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -1,25 +1,25 @@
<window:StyleableWindow <window:StyleableWindow
x:Class="Ryujinx.Ava.Ui.Windows.MainWindow" x:Class="Ryujinx.Ava.Ui.Windows.MainWindow"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
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:controls="clr-namespace:Ryujinx.Ava.Ui.Controls" xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
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:models="clr-namespace:Ryujinx.Ava.Ui.Models"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Title="Ryujinx" Title="Ryujinx"
Height="785"
Width="1280" Width="1280"
d:DesignHeight="720" Height="785"
d:DesignWidth="1280"
MinWidth="1024" MinWidth="1024"
MinHeight="680" MinHeight="680"
WindowStartupLocation="CenterScreen" d:DesignHeight="720"
d:DesignWidth="1280"
x:CompileBindings="True" x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel" x:DataType="viewModels:MainWindowViewModel"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d"> mc:Ignorable="d">
<Window.Styles> <Window.Styles>
<Style Selector="TitleBar:fullscreen"> <Style Selector="TitleBar:fullscreen">
@@ -38,23 +38,28 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<controls:OffscreenTextBox Name="HiddenTextBox" Grid.Row="0" /> <controls:OffscreenTextBox Name="HiddenTextBox" Grid.Row="0" />
<ContentControl Grid.Row="1" <ContentControl
Grid.Row="1"
Focusable="False" Focusable="False"
IsVisible="False" IsVisible="False"
KeyboardNavigation.IsTabStop="False"> KeyboardNavigation.IsTabStop="False">
<ui:ContentDialog Name="ContentDialog" <ui:ContentDialog
KeyboardNavigation.IsTabStop="False" Name="ContentDialog"
IsPrimaryButtonEnabled="True" IsPrimaryButtonEnabled="True"
IsSecondaryButtonEnabled="True" IsSecondaryButtonEnabled="True"
IsVisible="True" /> IsVisible="True"
KeyboardNavigation.IsTabStop="False" />
</ContentControl> </ContentControl>
<StackPanel IsVisible="False" Grid.Row="0"> <StackPanel Grid.Row="0" IsVisible="False">
<controls:HotKeyControl Name="FullscreenHotKey" Command="{ReflectionBinding ToggleFullscreen}" /> <controls:HotKeyControl Name="FullscreenHotKey" Command="{ReflectionBinding ToggleFullscreen}" />
<controls:HotKeyControl Name="FullscreenHotKey2" Command="{ReflectionBinding ToggleFullscreen}" /> <controls:HotKeyControl Name="FullscreenHotKey2" Command="{ReflectionBinding ToggleFullscreen}" />
<controls:HotKeyControl Name="DockToggleHotKey" Command="{ReflectionBinding ToggleDockMode}" /> <controls:HotKeyControl Name="DockToggleHotKey" Command="{ReflectionBinding ToggleDockMode}" />
<controls:HotKeyControl Name="ExitHotKey" Command="{ReflectionBinding ExitCurrentState}" /> <controls:HotKeyControl Name="ExitHotKey" Command="{ReflectionBinding ExitCurrentState}" />
</StackPanel> </StackPanel>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1"> <Grid
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@@ -73,47 +78,51 @@
<DockPanel HorizontalAlignment="Stretch"> <DockPanel HorizontalAlignment="Stretch">
<Menu <Menu
Name="Menu" Name="Menu"
Margin="0"
Height="35" Height="35"
Margin="0"
HorizontalAlignment="Left"> HorizontalAlignment="Left">
<Menu.ItemsPanel> <Menu.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<DockPanel HorizontalAlignment="Stretch" Margin="0" /> <DockPanel Margin="0" HorizontalAlignment="Stretch" />
</ItemsPanelTemplate> </ItemsPanelTemplate>
</Menu.ItemsPanel> </Menu.ItemsPanel>
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}">
<MenuItem <MenuItem
VerticalAlignment="Center"
Header="{locale:Locale MenuBarFile}">
<MenuItem IsEnabled="{Binding EnableNonGameRunningControls}"
Command="{ReflectionBinding OpenFile}" Command="{ReflectionBinding OpenFile}"
Header="{locale:Locale MenuBarFileOpenFromFile}" Header="{locale:Locale MenuBarFileOpenFromFile}"
IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" /> ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" />
<MenuItem IsEnabled="{Binding EnableNonGameRunningControls}" <MenuItem
Command="{ReflectionBinding OpenFolder}" Command="{ReflectionBinding OpenFolder}"
Header="{locale:Locale MenuBarFileOpenUnpacked}" Header="{locale:Locale MenuBarFileOpenUnpacked}"
IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" /> ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" />
<MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" <MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}">
IsEnabled="{Binding IsAppletMenuActive}"> <MenuItem
<MenuItem Command="{ReflectionBinding OpenMiiApplet}" Header="Mii Edit Applet" Command="{ReflectionBinding OpenMiiApplet}"
Header="Mii Edit Applet"
ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" /> ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Command="{ReflectionBinding OpenRyujinxFolder}" <MenuItem
Command="{ReflectionBinding OpenRyujinxFolder}"
Header="{locale:Locale MenuBarFileOpenEmuFolder}" Header="{locale:Locale MenuBarFileOpenEmuFolder}"
ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" /> ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" />
<MenuItem Command="{ReflectionBinding OpenLogsFolder}" <MenuItem
Command="{ReflectionBinding OpenLogsFolder}"
Header="{locale:Locale MenuBarFileOpenLogsFolder}" Header="{locale:Locale MenuBarFileOpenLogsFolder}"
ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" /> ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" />
<Separator /> <Separator />
<MenuItem Command="{ReflectionBinding CloseWindow}" <MenuItem
Command="{ReflectionBinding CloseWindow}"
Header="{locale:Locale MenuBarFileExit}" Header="{locale:Locale MenuBarFileExit}"
ToolTip.Tip="{locale:Locale ExitTooltip}" /> ToolTip.Tip="{locale:Locale ExitTooltip}" />
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}">
<MenuItem <MenuItem
VerticalAlignment="Center" Command="{ReflectionBinding ToggleFullscreen}"
Header="{locale:Locale MenuBarOptions}"> Header="{locale:Locale MenuBarOptionsToggleFullscreen}"
<MenuItem Command="{ReflectionBinding ToggleFullscreen}" InputGesture="F11" />
Header="{locale:Locale MenuBarOptionsToggleFullscreen}" InputGesture="F11" />
<MenuItem Header="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"> <MenuItem Header="{locale:Locale MenuBarOptionsStartGamesInFullscreen}">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}" /> <CheckBox IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}" />
@@ -126,60 +135,86 @@
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}"> <MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}">
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="en_US" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="en_US"
Header="American English" /> Header="American English" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="pt_BR" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="pt_BR"
Header="Brazilian Portuguese" /> Header="Brazilian Portuguese" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="es_ES" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="es_ES"
Header="Castilian Spanish" /> Header="Castilian Spanish" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="fr_FR" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="fr_FR"
Header="French" /> Header="French" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="de_DE" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="de_DE"
Header="German" /> Header="German" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="el_GR" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="el_GR"
Header="Greek" /> Header="Greek" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="it_IT" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="it_IT"
Header="Italian" /> Header="Italian" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="ko_KR" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="ko_KR"
Header="Korean" /> Header="Korean" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="ru_RU" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="ru_RU"
Header="Russian" /> Header="Russian" />
<MenuItem Command="{ReflectionBinding ChangeLanguage}" CommandParameter="tr_TR" <MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="tr_TR"
Header="Turkish" /> Header="Turkish" />
<MenuItem
Command="{ReflectionBinding ChangeLanguage}"
CommandParameter="zh_CN"
Header="Simplified Chinese" />
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Command="{ReflectionBinding OpenSettings}" <MenuItem
Command="{ReflectionBinding OpenSettings}"
Header="{locale:Locale MenuBarOptionsSettings}" Header="{locale:Locale MenuBarOptionsSettings}"
ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" /> ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" />
<MenuItem Command="{ReflectionBinding ManageProfiles}" <MenuItem
IsEnabled="{Binding EnableNonGameRunningControls}" Command="{ReflectionBinding ManageProfiles}"
Header="{locale:Locale MenuBarOptionsManageUserProfiles}" Header="{locale:Locale MenuBarOptionsManageUserProfiles}"
IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" /> ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" />
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Name="ActionsMenuItem"
VerticalAlignment="Center" VerticalAlignment="Center"
Header="{locale:Locale MenuBarActions}" Header="{locale:Locale MenuBarActions}"
Name="ActionsMenuItem"
IsEnabled="{Binding IsGameRunning}"> IsEnabled="{Binding IsGameRunning}">
<MenuItem <MenuItem
Click="PauseEmulation_Click" Click="PauseEmulation_Click"
Header="{locale:Locale MenuBarOptionsPauseEmulation}" Header="{locale:Locale MenuBarOptionsPauseEmulation}"
InputGesture="{Binding PauseKey}"
IsEnabled="{Binding !IsPaused}" IsEnabled="{Binding !IsPaused}"
IsVisible="{Binding !IsPaused}" IsVisible="{Binding !IsPaused}" />
InputGesture="{Binding PauseKey}" />
<MenuItem <MenuItem
Click="ResumeEmulation_Click" Click="ResumeEmulation_Click"
Header="{locale:Locale MenuBarOptionsResumeEmulation}" Header="{locale:Locale MenuBarOptionsResumeEmulation}"
InputGesture="{Binding PauseKey}"
IsEnabled="{Binding IsPaused}" IsEnabled="{Binding IsPaused}"
IsVisible="{Binding IsPaused}" IsVisible="{Binding IsPaused}" />
InputGesture="{Binding PauseKey}" />
<MenuItem <MenuItem
Click="StopEmulation_Click" Click="StopEmulation_Click"
Header="{locale:Locale MenuBarOptionsStopEmulation}" Header="{locale:Locale MenuBarOptionsStopEmulation}"
ToolTip.Tip="{locale:Locale StopEmulationTooltip}" InputGesture="Escape"
IsEnabled="{Binding IsGameRunning}" InputGesture="Escape" /> IsEnabled="{Binding IsGameRunning}"
<MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" ToolTip.Tip="{locale:Locale StopEmulationTooltip}" />
Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" /> <MenuItem Command="{ReflectionBinding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" />
<Separator /> <Separator />
<MenuItem <MenuItem
Name="ScanAmiiboMenuItem" Name="ScanAmiiboMenuItem"
@@ -187,39 +222,36 @@
Command="{ReflectionBinding OpenAmiiboWindow}" Command="{ReflectionBinding OpenAmiiboWindow}"
Header="{locale:Locale MenuBarActionsScanAmiibo}" Header="{locale:Locale MenuBarActionsScanAmiibo}"
IsEnabled="{Binding IsAmiiboRequested}" /> IsEnabled="{Binding IsAmiiboRequested}" />
<MenuItem Command="{ReflectionBinding TakeScreenshot}" <MenuItem
IsEnabled="{Binding IsGameRunning}" Command="{ReflectionBinding TakeScreenshot}"
Header="{locale:Locale MenuBarFileToolsTakeScreenshot}" Header="{locale:Locale MenuBarFileToolsTakeScreenshot}"
InputGesture="{Binding ScreenshotKey}" /> InputGesture="{Binding ScreenshotKey}"
<MenuItem Command="{ReflectionBinding HideUi}" IsEnabled="{Binding IsGameRunning}" />
IsEnabled="{Binding IsGameRunning}" <MenuItem
Command="{ReflectionBinding HideUi}"
Header="{locale:Locale MenuBarFileToolsHideUi}" Header="{locale:Locale MenuBarFileToolsHideUi}"
InputGesture="{Binding ShowUiKey}" /> InputGesture="{Binding ShowUiKey}"
<MenuItem Command="{ReflectionBinding OpenCheatManagerForCurrentApp}" IsEnabled="{Binding IsGameRunning}" />
IsEnabled="{Binding IsGameRunning}"
Header="{locale:Locale GameListContextMenuManageCheat}" />
</MenuItem>
<MenuItem <MenuItem
VerticalAlignment="Center" Command="{ReflectionBinding OpenCheatManagerForCurrentApp}"
Header="{locale:Locale MenuBarTools}"> Header="{locale:Locale GameListContextMenuManageCheat}"
<MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding IsGameRunning}" />
IsEnabled="{Binding EnableNonGameRunningControls}"> </MenuItem>
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}">
Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" /> <MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}">
<MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" <MenuItem Command="{ReflectionBinding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" />
Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" /> <MenuItem Command="{ReflectionBinding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" />
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}">
VerticalAlignment="Center"
Header="{locale:Locale MenuBarHelp}">
<MenuItem <MenuItem
Name="UpdateMenuItem" Name="UpdateMenuItem"
Command="{ReflectionBinding CheckForUpdates}" Command="{ReflectionBinding CheckForUpdates}"
Header="{locale:Locale MenuBarHelpCheckForUpdates}" Header="{locale:Locale MenuBarHelpCheckForUpdates}"
ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" /> ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" />
<Separator /> <Separator />
<MenuItem Command="{ReflectionBinding OpenAboutWindow}" <MenuItem
Command="{ReflectionBinding OpenAboutWindow}"
Header="{locale:Locale MenuBarHelpAbout}" Header="{locale:Locale MenuBarHelpAbout}"
ToolTip.Tip="{locale:Locale OpenAboutTooltip}" /> ToolTip.Tip="{locale:Locale OpenAboutTooltip}" />
</MenuItem> </MenuItem>
@@ -230,152 +262,213 @@
Name="Content" Name="Content"
Grid.Row="1" Grid.Row="1"
Padding="0" Padding="0"
IsVisible="{Binding ShowContent}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
BorderBrush="{DynamicResource ThemeControlBorderColor}" BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="0,0,0,0" BorderThickness="0,0,0,0"
DockPanel.Dock="Top"> DockPanel.Dock="Top"
IsVisible="{Binding ShowContent}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DockPanel Grid.Row="0" HorizontalAlignment="Stretch" Margin="0,0,0,5"> <DockPanel
Grid.Row="0"
Margin="0,0,0,5"
HorizontalAlignment="Stretch">
<Button <Button
IsEnabled="{Binding IsGrid}" VerticalAlignment="Stretch" MinWidth="40" Width="40" Width="40"
Margin="5,2,0,2" Command="{ReflectionBinding SetListMode}"> MinWidth="40"
<ui:FontIcon FontFamily="avares://FluentAvalonia/Fonts#Symbols" Margin="5,2,0,2"
VerticalAlignment="Center" VerticalAlignment="Stretch"
Command="{ReflectionBinding SetListMode}"
IsEnabled="{Binding IsGrid}">
<ui:FontIcon
Margin="0" Margin="0"
Glyph="{controls:GlyphValueConverter List}" HorizontalAlignment="Stretch"
HorizontalAlignment="Stretch" /> VerticalAlignment="Center"
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
Glyph="{controls:GlyphValueConverter List}" />
</Button> </Button>
<Button <Button
IsEnabled="{Binding IsList}" VerticalAlignment="Stretch" MinWidth="40" Width="40" Width="40"
Margin="5,2,5,2" Command="{ReflectionBinding SetGridMode}"> MinWidth="40"
<ui:FontIcon FontFamily="avares://FluentAvalonia/Fonts#Symbols" Margin="5,2,5,2"
VerticalAlignment="Center" VerticalAlignment="Stretch"
Command="{ReflectionBinding SetGridMode}"
IsEnabled="{Binding IsList}">
<ui:FontIcon
Margin="0" Margin="0"
Glyph="{controls:GlyphValueConverter Grid}" HorizontalAlignment="Stretch"
HorizontalAlignment="Stretch" /> VerticalAlignment="Center"
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
Glyph="{controls:GlyphValueConverter Grid}" />
</Button> </Button>
<TextBlock Text="{locale:Locale IconSize}" <TextBlock
VerticalAlignment="Center" Margin="10,0" Margin="10,0"
VerticalAlignment="Center"
Text="{locale:Locale IconSize}"
ToolTip.Tip="{locale:Locale IconSizeTooltip}" /> ToolTip.Tip="{locale:Locale IconSizeTooltip}" />
<Slider Width="150" Margin="5,-10,5 ,0" Height="35" <Slider
Width="150"
Height="35"
Margin="5,-10,5,0"
VerticalAlignment="Center"
IsSnapToTickEnabled="True"
Maximum="4"
Minimum="1"
TickFrequency="1"
ToolTip.Tip="{locale:Locale IconSizeTooltip}" ToolTip.Tip="{locale:Locale IconSizeTooltip}"
VerticalAlignment="Center" Minimum="1" Maximum="4" IsSnapToTickEnabled="True" Value="{Binding GridSizeScale}" />
TickFrequency="1" Value="{Binding GridSizeScale}" /> <CheckBox
<CheckBox Margin="0" IsChecked="{Binding ShowNames, Mode=TwoWay}" VerticalAlignment="Center" Margin="0"
VerticalAlignment="Center"
IsChecked="{Binding ShowNames, Mode=TwoWay}"
IsVisible="{Binding IsGrid}"> IsVisible="{Binding IsGrid}">
<TextBlock Text="{locale:Locale CommonShowNames}" Margin="5,3,0,0" /> <TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" />
</CheckBox> </CheckBox>
<TextBox <TextBox
Name="SearchBox" Name="SearchBox"
DockPanel.Dock="Right"
VerticalAlignment="Center"
MinWidth="200" MinWidth="200"
Margin="5,0,5,0" Margin="5,0,5,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center"
DockPanel.Dock="Right"
KeyUp="SearchBox_OnKeyUp" KeyUp="SearchBox_OnKeyUp"
Text="{Binding SearchText}" Text="{Binding SearchText}"
Watermark="{locale:Locale MenuSearch}" /> Watermark="{locale:Locale MenuSearch}" />
<ui:DropDownButton DockPanel.Dock="Right" <ui:DropDownButton
HorizontalAlignment="Right" Width="150" VerticalAlignment="Center" Width="150"
Content="{Binding SortName}"> HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{Binding SortName}"
DockPanel.Dock="Right">
<ui:DropDownButton.Flyout> <ui:DropDownButton.Flyout>
<Flyout Placement="Bottom"> <Flyout Placement="Bottom">
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="0"> <StackPanel
Margin="0"
HorizontalAlignment="Stretch"
Orientation="Vertical">
<StackPanel> <StackPanel>
<RadioButton Tag="Favorite" <RadioButton
IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}" Checked="Sort_Checked"
GroupName="Sort"
Content="{locale:Locale CommonFavorite}" Content="{locale:Locale CommonFavorite}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="Title" GroupName="Sort" IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}"
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}" Tag="Favorite" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderApplication}" Content="{locale:Locale GameListHeaderApplication}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="Developer" GroupName="Sort" IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}" Tag="Title" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderDeveloper}" Content="{locale:Locale GameListHeaderDeveloper}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="TotalTimePlayed" GroupName="Sort" IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}"
IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}" Tag="Developer" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderTimePlayed}" Content="{locale:Locale GameListHeaderTimePlayed}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="LastPlayed" GroupName="Sort" IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}"
IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}" Tag="TotalTimePlayed" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderLastPlayed}" Content="{locale:Locale GameListHeaderLastPlayed}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="FileType" GroupName="Sort" IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}"
IsChecked="{Binding IsSortedByType, Mode=OneTime}" Tag="LastPlayed" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderFileExtension}" Content="{locale:Locale GameListHeaderFileExtension}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="FileSize" GroupName="Sort" IsChecked="{Binding IsSortedByType, Mode=OneTime}"
IsChecked="{Binding IsSortedBySize, Mode=OneTime}" Tag="FileType" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderFileSize}" Content="{locale:Locale GameListHeaderFileSize}"
Checked="Sort_Checked" /> GroupName="Sort"
<RadioButton Tag="Path" GroupName="Sort" IsChecked="{Binding IsSortedBySize, Mode=OneTime}"
IsChecked="{Binding IsSortedByPath, Mode=OneTime}" Tag="FileSize" />
<RadioButton
Checked="Sort_Checked"
Content="{locale:Locale GameListHeaderPath}" Content="{locale:Locale GameListHeaderPath}"
Checked="Sort_Checked" /> GroupName="Sort"
IsChecked="{Binding IsSortedByPath, Mode=OneTime}"
Tag="Path" />
</StackPanel> </StackPanel>
<Border HorizontalAlignment="Stretch" Margin="5" Height="2" BorderBrush="White" <Border
Width="60" BorderThickness="0,1,0,0"> Width="60"
<Separator HorizontalAlignment="Stretch" Height="0" /> Height="2"
Margin="5"
HorizontalAlignment="Stretch"
BorderBrush="White"
BorderThickness="0,1,0,0">
<Separator Height="0" HorizontalAlignment="Stretch" />
</Border> </Border>
<RadioButton Tag="Ascending" IsChecked="{Binding IsAscending, Mode=OneTime}" <RadioButton
Checked="Order_Checked"
Content="{locale:Locale OrderAscending}"
GroupName="Order"
IsChecked="{Binding IsAscending, Mode=OneTime}"
Tag="Ascending" />
<RadioButton
Checked="Order_Checked"
Content="{locale:Locale OrderDescending}"
GroupName="Order" GroupName="Order"
Content="{locale:Locale OrderAscending}" Checked="Order_Checked" />
<RadioButton Tag="Descending" GroupName="Order"
IsChecked="{Binding !IsAscending, Mode=OneTime}" IsChecked="{Binding !IsAscending, Mode=OneTime}"
Content="{locale:Locale OrderDescending}" Checked="Order_Checked" /> Tag="Descending" />
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</ui:DropDownButton.Flyout> </ui:DropDownButton.Flyout>
</ui:DropDownButton> </ui:DropDownButton>
<TextBlock DockPanel.Dock="Right" HorizontalAlignment="Right" <TextBlock
Text="{locale:Locale CommonSort}" VerticalAlignment="Center" Margin="10,0" /> Margin="10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
DockPanel.Dock="Right"
Text="{locale:Locale CommonSort}" />
</DockPanel> </DockPanel>
<controls:GameListView <controls:GameListView
x:Name="GameList" x:Name="GameList"
Grid.Row="1" Grid.Row="1"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
IsVisible="{Binding IsList}" /> IsVisible="{Binding IsList}" />
<controls:GameGridView <controls:GameGridView
x:Name="GameGrid" x:Name="GameGrid"
Grid.Row="1" Grid.Row="1"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
IsVisible="{Binding IsGrid}" /> IsVisible="{Binding IsGrid}" />
</Grid> </Grid>
</ContentControl> </ContentControl>
<Grid Grid.Row="1" <Grid
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Background="{DynamicResource ThemeContentBackgroundColor}" Background="{DynamicResource ThemeContentBackgroundColor}"
IsVisible="{Binding ShowLoadProgress}" IsVisible="{Binding ShowLoadProgress}"
ZIndex="1000" ZIndex="1000">
HorizontalAlignment="Stretch">
<Grid <Grid
HorizontalAlignment="Center"
IsVisible="{Binding ShowLoadProgress}"
Margin="40" Margin="40"
VerticalAlignment="Center"> HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{Binding ShowLoadProgress}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Border <Border
Grid.Column="0"
Grid.RowSpan="2" Grid.RowSpan="2"
IsVisible="{Binding ShowLoadProgress}" Grid.Column="0"
Width="256" Width="256"
Height="256" Height="256"
Margin="10" Margin="10"
@@ -383,62 +476,64 @@
BorderBrush="Black" BorderBrush="Black"
BorderThickness="2" BorderThickness="2"
BoxShadow="4 4 32 8 #40000000" BoxShadow="4 4 32 8 #40000000"
CornerRadius="3"> CornerRadius="3"
IsVisible="{Binding ShowLoadProgress}">
<Image <Image
IsVisible="{Binding ShowLoadProgress}"
Width="256" Width="256"
Height="256" Height="256"
IsVisible="{Binding ShowLoadProgress}"
Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" /> Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" />
</Border> </Border>
<Grid Grid.Column="1" <Grid
IsVisible="{Binding ShowLoadProgress}" Grid.Column="1"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center"> VerticalAlignment="Center"
IsVisible="{Binding ShowLoadProgress}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock <TextBlock
IsVisible="{Binding ShowLoadProgress}"
Grid.Row="0" Grid.Row="0"
Margin="10" Margin="10"
FontSize="30" FontSize="30"
FontWeight="Bold" FontWeight="Bold"
TextWrapping="Wrap"
Text="{Binding LoadHeading}"
TextAlignment="Left" />
<Border
IsVisible="{Binding ShowLoadProgress}" IsVisible="{Binding ShowLoadProgress}"
Text="{Binding LoadHeading}"
TextAlignment="Left"
TextWrapping="Wrap" />
<Border
Grid.Row="1" Grid.Row="1"
CornerRadius="5" Margin="10"
ClipToBounds="True"
BorderBrush="{Binding ProgressBarBackgroundColor}"
Padding="0" Padding="0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="10" BorderBrush="{Binding ProgressBarBackgroundColor}"
BorderThickness="1"> BorderThickness="1"
ClipToBounds="True"
CornerRadius="5"
IsVisible="{Binding ShowLoadProgress}">
<ProgressBar <ProgressBar
IsVisible="{Binding ShowLoadProgress}"
Height="10" Height="10"
MinWidth="500"
Margin="0" Margin="0"
Padding="0" Padding="0"
CornerRadius="5"
ClipToBounds="True"
MinWidth="500"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Background="{Binding ProgressBarBackgroundColor}" Background="{Binding ProgressBarBackgroundColor}"
ClipToBounds="True"
CornerRadius="5"
Foreground="{Binding ProgressBarForegroundColor}" Foreground="{Binding ProgressBarForegroundColor}"
IsIndeterminate="{Binding IsLoadingIndeterminate}"
IsVisible="{Binding ShowLoadProgress}"
Maximum="{Binding ProgressMaximum}" Maximum="{Binding ProgressMaximum}"
Minimum="0" Minimum="0"
IsIndeterminate="{Binding IsLoadingIndeterminate}"
Value="{Binding ProgressValue}" /> Value="{Binding ProgressValue}" />
</Border> </Border>
<TextBlock <TextBlock
IsVisible="{Binding ShowLoadProgress}"
Grid.Row="2" Grid.Row="2"
Margin="10" Margin="10"
FontSize="18" FontSize="18"
IsVisible="{Binding ShowLoadProgress}"
Text="{Binding CacheLoadStatus}" Text="{Binding CacheLoadStatus}"
TextAlignment="Left" /> TextAlignment="Left" />
</Grid> </Grid>
@@ -450,8 +545,8 @@
Height="30" Height="30"
Margin="0,0" Margin="0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Background="{DynamicResource ThemeContentBackgroundColor}"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
Background="{DynamicResource ThemeContentBackgroundColor}"
DockPanel.Dock="Bottom" DockPanel.Dock="Bottom"
IsVisible="{Binding ShowMenuAndStatusBar}"> IsVisible="{Binding ShowMenuAndStatusBar}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -460,8 +555,11 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" IsVisible="{Binding EnableNonGameRunningControls}" <StackPanel
VerticalAlignment="Center" Margin="10,0"> Grid.Column="0"
Margin="10,0"
VerticalAlignment="Center"
IsVisible="{Binding EnableNonGameRunningControls}">
<Grid Margin="0"> <Grid Margin="0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -476,7 +574,10 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Background="Transparent" Background="Transparent"
Command="{ReflectionBinding LoadApplications}"> Command="{ReflectionBinding LoadApplications}">
<ui:SymbolIcon Symbol="Refresh" Height="100" Width="50" /> <ui:SymbolIcon
Width="50"
Height="100"
Symbol="Refresh" />
</Button> </Button>
<TextBlock <TextBlock
Name="LoadStatus" Name="LoadStatus"
@@ -489,11 +590,11 @@
Name="LoadProgressBar" Name="LoadProgressBar"
Grid.Column="2" Grid.Column="2"
Height="6" Height="6"
Maximum="{Binding StatusBarProgressMaximum}"
Value="{Binding StatusBarProgressValue}"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource HighlightColor}" Foreground="{DynamicResource HighlightColor}"
IsVisible="{Binding EnableNonGameRunningControls}" /> IsVisible="{Binding EnableNonGameRunningControls}"
Maximum="{Binding StatusBarProgressMaximum}"
Value="{Binding StatusBarProgressValue}" />
</Grid> </Grid>
</StackPanel> </StackPanel>
<StackPanel <StackPanel
@@ -505,132 +606,137 @@
Orientation="Horizontal"> Orientation="Horizontal">
<TextBlock <TextBlock
Name="VsyncStatus" Name="VsyncStatus"
Margin="0,0,5,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{Binding VsyncColor}" Foreground="{Binding VsyncColor}"
PointerReleased="VsyncStatus_PointerReleased"
IsVisible="{Binding !ShowLoadProgress}" IsVisible="{Binding !ShowLoadProgress}"
Margin="0,0,5,0" PointerReleased="VsyncStatus_PointerReleased"
Text="VSync" Text="VSync"
TextAlignment="Left" /> TextAlignment="Left" />
<Border <Border
Width="2" Width="2"
Margin="2,0"
IsVisible="{Binding !ShowLoadProgress}"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
Margin="5,0,5,0"
Name="DockedStatus" Name="DockedStatus"
IsVisible="{Binding !ShowLoadProgress}" Margin="5,0,5,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
PointerReleased="DockedStatus_PointerReleased" PointerReleased="DockedStatus_PointerReleased"
Text="{Binding DockedStatusText}" Text="{Binding DockedStatusText}"
TextAlignment="Left" /> TextAlignment="Left" />
<Border <Border
Width="2" Width="2"
Margin="2,0"
IsVisible="{Binding !ShowLoadProgress}"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
Margin="5,0,5,0"
Name="AspectRatioStatus" Name="AspectRatioStatus"
IsVisible="{Binding !ShowLoadProgress}" Margin="5,0,5,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
PointerReleased="AspectRatioStatus_PointerReleased" PointerReleased="AspectRatioStatus_PointerReleased"
Text="{Binding AspectRatioStatusText}" Text="{Binding AspectRatioStatusText}"
TextAlignment="Left" /> TextAlignment="Left" />
<Border <Border
Width="2" Width="2"
Margin="2,0"
IsVisible="{Binding !ShowLoadProgress}"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<ui:ToggleSplitButton <ui:ToggleSplitButton
Name="VolumeStatus"
Margin="-2,0,-3,0" Margin="-2,0,-3,0"
Padding="5,0,0,5" Padding="5,0,0,5"
Name="VolumeStatus"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
BorderBrush="{DynamicResource ThemeContentBackgroundColor}"
Background="{DynamicResource ThemeContentBackgroundColor}" Background="{DynamicResource ThemeContentBackgroundColor}"
BorderBrush="{DynamicResource ThemeContentBackgroundColor}"
Content="{Binding VolumeStatusText}"
IsChecked="{Binding VolumeMuted}" IsChecked="{Binding VolumeMuted}"
Content="{Binding VolumeStatusText}"> IsVisible="{Binding !ShowLoadProgress}">
<ui:ToggleSplitButton.Flyout> <ui:ToggleSplitButton.Flyout>
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway"> <Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
<Grid Margin="0"> <Grid Margin="0">
<Slider Value="{Binding Volume}" <Slider
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}" Width="150"
Minimum="0"
Maximum="1"
TickFrequency="0.05"
IsSnapToTickEnabled="True"
Padding="0"
Margin="0" Margin="0"
SmallChange="0.01" Padding="0"
IsSnapToTickEnabled="True"
LargeChange="0.05" LargeChange="0.05"
Width="150" /> Maximum="1"
Minimum="0"
SmallChange="0.01"
TickFrequency="0.05"
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
Value="{Binding Volume}" />
</Grid> </Grid>
</Flyout> </Flyout>
</ui:ToggleSplitButton.Flyout> </ui:ToggleSplitButton.Flyout>
</ui:ToggleSplitButton> </ui:ToggleSplitButton>
<Border <Border
Width="2" Width="2"
Margin="2,0"
IsVisible="{Binding !ShowLoadProgress}"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
Margin="5,0,5,0" Margin="5,0,5,0"
IsVisible="{Binding !ShowLoadProgress}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
Text="{Binding GameStatusText}" Text="{Binding GameStatusText}"
TextAlignment="Left" /> TextAlignment="Left" />
<Border <Border
Width="2" Width="2"
IsVisible="{Binding !ShowLoadProgress}"
Margin="2,0"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
Margin="5,0,5,0" Margin="5,0,5,0"
IsVisible="{Binding !ShowLoadProgress}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
Text="{Binding FifoStatusText}" Text="{Binding FifoStatusText}"
TextAlignment="Left" /> TextAlignment="Left" />
<Border <Border
Width="2" Width="2"
Margin="2,0"
IsVisible="{Binding !ShowLoadProgress}"
BorderThickness="1"
Height="12" Height="12"
BorderBrush="Gray" /> Margin="2,0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding !ShowLoadProgress}" />
<TextBlock <TextBlock
Margin="5,0,5,0" Margin="5,0,5,0"
IsVisible="{Binding !ShowLoadProgress}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding !ShowLoadProgress}"
Text="{Binding GpuStatusText}" Text="{Binding GpuStatusText}"
TextAlignment="Left" /> TextAlignment="Left" />
</StackPanel> </StackPanel>
<StackPanel VerticalAlignment="Center" IsVisible="{Binding ShowFirmwareStatus}" Grid.Column="3" <StackPanel
Orientation="Horizontal" Margin="10, 0"> Grid.Column="3"
Margin="10,0"
VerticalAlignment="Center"
IsVisible="{Binding ShowFirmwareStatus}"
Orientation="Horizontal">
<TextBlock <TextBlock
Name="FirmwareStatus" Name="FirmwareStatus"
Margin="0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="0"
Text="{locale:Locale StatusBarSystemVersion}" /> Text="{locale:Locale StatusBarSystemVersion}" />
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -1,18 +1,26 @@
<window:StyleableWindow xmlns="https://github.com/avaloniaui" <window:StyleableWindow
x:Class="Ryujinx.Ava.Ui.Windows.UpdaterWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="350"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
x:Class="Ryujinx.Ava.Ui.Windows.UpdaterWindow" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Title="Ryujinx Updater"
Width="500"
Height="500"
MinWidth="500"
MinHeight="500"
d:DesignHeight="350"
d:DesignWidth="400"
CanResize="False" CanResize="False"
SizeToContent="Height" SizeToContent="Height"
Width="500" MinHeight="500" Height="500"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
MinWidth="500" mc:Ignorable="d">
Title="Ryujinx Updater"> <Grid
<Grid Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> Margin="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
@@ -20,17 +28,38 @@
<RowDefinition /> <RowDefinition />
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="1" HorizontalAlignment="Stretch" TextAlignment="Center" Height="20" Name="MainText" /> <TextBlock
<TextBlock Height="20" HorizontalAlignment="Stretch" TextAlignment="Center" Name="SecondaryText" Grid.Row="2" /> Name="MainText"
<ProgressBar IsVisible="False" HorizontalAlignment="Stretch" Name="ProgressBar" Maximum="100" Minimum="0" Grid.Row="1"
Margin="20" Grid.Row="3" /> Height="20"
<StackPanel IsVisible="False" Name="ButtonBox" Orientation="Horizontal" Spacing="20" Grid.Row="4" HorizontalAlignment="Stretch"
HorizontalAlignment="Right"> TextAlignment="Center" />
<Button Command="{Binding YesPressed}" MinWidth="50"> <TextBlock
<TextBlock TextAlignment="Center" Text="{locale:Locale InputDialogYes}" /> Name="SecondaryText"
Grid.Row="2"
Height="20"
HorizontalAlignment="Stretch"
TextAlignment="Center" />
<ProgressBar
Name="ProgressBar"
Grid.Row="3"
Margin="20"
HorizontalAlignment="Stretch"
IsVisible="False"
Maximum="100"
Minimum="0" />
<StackPanel
Name="ButtonBox"
Grid.Row="4"
HorizontalAlignment="Right"
IsVisible="False"
Orientation="Horizontal"
Spacing="20">
<Button MinWidth="50" Command="{Binding YesPressed}">
<TextBlock Text="{locale:Locale InputDialogYes}" TextAlignment="Center" />
</Button> </Button>
<Button Command="{Binding NoPressed}" MinWidth="50"> <Button MinWidth="50" Command="{Binding NoPressed}">
<TextBlock TextAlignment="Center" Text="{locale:Locale InputDialogNo}" /> <TextBlock Text="{locale:Locale InputDialogNo}" TextAlignment="Center" />
</Button> </Button>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.Common.Memory
{
public class Box<T> where T : unmanaged
{
public T Data;
public Box()
{
Data = new T();
}
}
}

View File

@@ -101,6 +101,16 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The GPU resource with the given ID</returns> /// <returns>The GPU resource with the given ID</returns>
public abstract T1 Get(int id); public abstract T1 Get(int id);
/// <summary>
/// Checks if a given ID is valid and inside the range of the pool.
/// </summary>
/// <param name="id">ID of the descriptor. This is effectively a zero-based index</param>
/// <returns>True if the specified ID is valid, false otherwise</returns>
public bool IsValidId(int id)
{
return (uint)id <= MaximumId;
}
/// <summary> /// <summary>
/// Synchronizes host memory with guest memory. /// Synchronizes host memory with guest memory.
/// This causes invalidation of pool entries, /// This causes invalidation of pool entries,

View File

@@ -32,6 +32,9 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly GpuChannel _channel; private readonly GpuChannel _channel;
private readonly TexturePoolCache _texturePoolCache; private readonly TexturePoolCache _texturePoolCache;
private TexturePool _cachedTexturePool;
private SamplerPool _cachedSamplerPool;
private readonly TextureBindingInfo[][] _textureBindings; private readonly TextureBindingInfo[][] _textureBindings;
private readonly TextureBindingInfo[][] _imageBindings; private readonly TextureBindingInfo[][] _imageBindings;
@@ -343,9 +346,14 @@ namespace Ryujinx.Graphics.Gpu.Image
? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId) ? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId)
: null; : null;
SamplerPool samplerPool = _samplerPool;
// Check if the texture pool has been modified since bindings were last committed. // Check if the texture pool has been modified since bindings were last committed.
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same. // If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
bool poolModified = false; bool poolModified = _cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool;
_cachedTexturePool = texturePool;
_cachedSamplerPool = samplerPool;
if (texturePool != null) if (texturePool != null)
{ {
@@ -358,9 +366,9 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
if (_samplerPool != null) if (samplerPool != null)
{ {
int samplerPoolSequence = _samplerPool.CheckModified(); int samplerPoolSequence = samplerPool.CheckModified();
if (_samplerPoolSequence != samplerPoolSequence) if (_samplerPoolSequence != samplerPoolSequence)
{ {
@@ -738,7 +746,22 @@ namespace Ryujinx.Graphics.Gpu.Image
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId);
return texturePool.GetDescriptor(textureId); TextureDescriptor descriptor;
if (texturePool.IsValidId(textureId))
{
descriptor = texturePool.GetDescriptor(textureId);
}
else
{
// If the ID is not valid, we just return a default descriptor with the most common state.
// Since this is used for shader specialization, doing so might avoid the need for recompilations.
descriptor = new TextureDescriptor();
descriptor.Word4 |= (uint)TextureTarget.Texture2D << 23;
descriptor.Word5 |= 1u << 31; // Coords normalized.
}
return descriptor;
} }
/// <summary> /// <summary>

View File

@@ -241,25 +241,6 @@ namespace Ryujinx.Graphics.Gpu.Image
return (TextureMsaaMode)((Word7 >> 8) & 0xf); return (TextureMsaaMode)((Word7 >> 8) & 0xf);
} }
/// <summary>
/// Create the equivalent of this TextureDescriptor for the shader cache.
/// </summary>
/// <returns>The equivalent of this TextureDescriptor for the shader cache.</returns>
public GuestTextureDescriptor ToCache()
{
GuestTextureDescriptor result = new GuestTextureDescriptor
{
Handle = uint.MaxValue,
Format = UnpackFormat(),
Target = UnpackTextureTarget(),
IsSrgb = UnpackSrgb(),
IsTextureCoordNormalized = UnpackTextureCoordNormalized(),
};
return result;
}
/// <summary> /// <summary>
/// Check if two descriptors are equal. /// Check if two descriptors are equal.
/// </summary> /// </summary>

View File

@@ -579,9 +579,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
textureKey.StageIndex); textureKey.StageIndex);
int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer); int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer);
int textureId = TextureHandle.UnpackTextureId(packedId); int textureId = TextureHandle.UnpackTextureId(packedId);
if (pool.IsValidId(textureId))
{
ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId); ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId);
if (!MatchesTexture(kv.Value, descriptor)) if (!MatchesTexture(kv.Value, descriptor))
@@ -590,6 +591,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
} }
} }
} }
}
return true; return true;
} }

View File

@@ -966,6 +966,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
SignalExitToDebugExited(); SignalExitToDebugExited();
SignalExit(); SignalExit();
} }
KernelStatic.GetCurrentThread().Exit();
} }
private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread) private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread)
@@ -981,7 +983,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
foreach (KThread thread in _threads) foreach (KThread thread in _threads)
{ {
if ((thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending) if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
{ {
thread.PrepareForTermination(); thread.PrepareForTermination();
} }

View File

@@ -2,7 +2,10 @@ using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using Ryujinx.Memory;
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace Ryujinx.HLE.HOS.Services.Time.StaticService namespace Ryujinx.HLE.HOS.Services.Time.StaticService
@@ -100,15 +103,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
string locationName = StringUtils.ReadInlinedAsciiString(context.RequestData, 0x24); string locationName = StringUtils.ReadInlinedAsciiString(context.RequestData, 0x24);
ResultCode resultCode = _timeZoneContentManager.LoadTimeZoneRule(out TimeZoneRule rules, locationName); using (WritableRegion region = context.Memory.GetWritableRegion(bufferPosition, Unsafe.SizeOf<TimeZoneRule>()))
// Write TimeZoneRule if success
if (resultCode == ResultCode.Success)
{ {
MemoryHelper.Write(context.Memory, bufferPosition, rules); ref TimeZoneRule rules = ref MemoryMarshal.Cast<byte, TimeZoneRule>(region.Memory.Span)[0];
}
return resultCode; return _timeZoneContentManager.LoadTimeZoneRule(ref rules, locationName);
}
} }
[CommandHipc(100)] [CommandHipc(100)]

View File

@@ -4,9 +4,12 @@ using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using Ryujinx.Memory;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.StaticService namespace Ryujinx.HLE.HOS.Services.Time.StaticService
{ {
@@ -165,11 +168,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
using (MemoryStream timeZoneBinaryStream = new MemoryStream(temp)) using (MemoryStream timeZoneBinaryStream = new MemoryStream(temp))
{ {
result = _timeZoneManager.ParseTimeZoneRuleBinary(out TimeZoneRule timeZoneRule, timeZoneBinaryStream); using (WritableRegion region = context.Memory.GetWritableRegion(timeZoneRuleBufferPosition, Unsafe.SizeOf<TimeZoneRule>()))
if (result == ResultCode.Success)
{ {
MemoryHelper.Write(context.Memory, timeZoneRuleBufferPosition, timeZoneRule); ref TimeZoneRule rule = ref MemoryMarshal.Cast<byte, TimeZoneRule>(region.Memory.Span)[0];
result = _timeZoneManager.ParseTimeZoneRuleBinary(ref rule, timeZoneBinaryStream);
} }
} }
@@ -199,9 +202,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, bufferPosition); ReadOnlySpan<TimeZoneRule> rules = MemoryMarshal.Cast<byte, TimeZoneRule>(context.Memory.GetSpan(bufferPosition, (int)bufferSize));
ResultCode resultCode = _timeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar); ResultCode resultCode = _timeZoneManager.ToCalendarTime(in rules[0], posixTime, out CalendarInfo calendar);
if (resultCode == 0) if (resultCode == 0)
{ {
@@ -244,9 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, inBufferPosition); ReadOnlySpan<TimeZoneRule> rules = MemoryMarshal.Cast<byte, TimeZoneRule>(context.Memory.GetSpan(inBufferPosition, (int)inBufferSize));
ResultCode resultCode = _timeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime); ResultCode resultCode = _timeZoneManager.ToPosixTime(in rules[0], calendarTime, out long posixTime);
if (resultCode == ResultCode.Success) if (resultCode == ResultCode.Success)
{ {

View File

@@ -1,4 +1,5 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
@@ -38,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
}; };
private const string TimeZoneDefaultRule = ",M4.1.0,M10.5.0"; private static readonly byte[] TimeZoneDefaultRule = Encoding.ASCII.GetBytes(",M4.1.0,M10.5.0");
[StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x10)] [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x10)]
private struct CalendarTimeInternal private struct CalendarTimeInternal
@@ -133,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return (t1 - t0) == SecondsPerRepeat; return (t1 - t0) == SecondsPerRepeat;
} }
private static bool TimeTypeEquals(TimeZoneRule outRules, byte aIndex, byte bIndex) private static bool TimeTypeEquals(in TimeZoneRule outRules, byte aIndex, byte bIndex)
{ {
if (aIndex < 0 || aIndex >= outRules.TypeCount || bIndex < 0 || bIndex >= outRules.TypeCount) if (aIndex < 0 || aIndex >= outRules.TypeCount || bIndex < 0 || bIndex >= outRules.TypeCount)
{ {
@@ -150,7 +151,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
StringUtils.CompareCStr(outRules.Chars[a.AbbreviationListIndex..], outRules.Chars[b.AbbreviationListIndex..]) == 0; StringUtils.CompareCStr(outRules.Chars[a.AbbreviationListIndex..], outRules.Chars[b.AbbreviationListIndex..]) == 0;
} }
private static int GetQZName(ReadOnlySpan<char> name, int namePosition, char delimiter) private static int GetQZName(ReadOnlySpan<byte> name, int namePosition, char delimiter)
{ {
int i = namePosition; int i = namePosition;
@@ -162,13 +163,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return i; return i;
} }
private static int GetTZName(char[] name, int namePosition) private static int GetTZName(ReadOnlySpan<byte> name, int namePosition)
{ {
int i = namePosition; int i = namePosition;
char c; char c;
while ((c = name[i]) != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+') while ((c = (char)name[i]) != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+')
{ {
i++; i++;
} }
@@ -176,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return i; return i;
} }
private static bool GetNum(char[] name, ref int namePosition, out int num, int min, int max) private static bool GetNum(ReadOnlySpan<byte> name, ref int namePosition, out int num, int min, int max)
{ {
num = 0; num = 0;
@@ -185,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
char c = name[namePosition]; char c = (char)name[namePosition];
if (!char.IsDigit(c)) if (!char.IsDigit(c))
{ {
@@ -205,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
c = name[namePosition]; c = (char)name[namePosition];
} }
while (char.IsDigit(c)); while (char.IsDigit(c));
@@ -217,7 +218,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static bool GetSeconds(char[] name, ref int namePosition, out int seconds) private static bool GetSeconds(ReadOnlySpan<byte> name, ref int namePosition, out int seconds)
{ {
seconds = 0; seconds = 0;
@@ -266,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static bool GetOffset(char[] name, ref int namePosition, ref int offset) private static bool GetOffset(ReadOnlySpan<byte> name, ref int namePosition, ref int offset)
{ {
bool isNegative = false; bool isNegative = false;
@@ -304,7 +305,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static bool GetRule(char[] name, ref int namePosition, out Rule rule) private static bool GetRule(ReadOnlySpan<byte> name, ref int namePosition, out Rule rule)
{ {
rule = new Rule(); rule = new Rule();
@@ -347,7 +348,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerWekk - 1); isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerWekk - 1);
} }
else if (char.IsDigit(name[namePosition])) else if (char.IsDigit((char)name[namePosition]))
{ {
rule.Type = RuleType.DayOfYear; rule.Type = RuleType.DayOfYear;
isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerLYear - 1); isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerLYear - 1);
@@ -385,19 +386,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return 0; return 0;
} }
private static bool ParsePosixName(ReadOnlySpan<char> name, out TimeZoneRule outRules, bool lastDitch) private static bool ParsePosixName(ReadOnlySpan<byte> name, ref TimeZoneRule outRules, bool lastDitch)
{ {
outRules = new TimeZoneRule outRules = new TimeZoneRule();
{
Ats = new long[TzMaxTimes],
Types = new byte[TzMaxTimes],
Ttis = new TimeTypeInfo[TzMaxTypes],
Chars = new char[TzCharsArraySize]
};
int stdLen; int stdLen;
ReadOnlySpan<char> stdName = name; ReadOnlySpan<byte> stdName = name;
int namePosition = 0; int namePosition = 0;
int stdOffset = 0; int stdOffset = 0;
@@ -428,7 +423,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
else else
{ {
namePosition = GetTZName(name.ToArray(), namePosition); namePosition = GetTZName(name, namePosition);
stdLen = namePosition; stdLen = namePosition;
} }
@@ -449,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int destLen = 0; int destLen = 0;
int dstOffset = 0; int dstOffset = 0;
ReadOnlySpan<char> destName = name.Slice(namePosition); ReadOnlySpan<byte> destName = name.Slice(namePosition);
if (TzCharsArraySize < charCount) if (TzCharsArraySize < charCount)
{ {
@@ -476,7 +471,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
else else
{ {
destName = name.Slice(namePosition); destName = name.Slice(namePosition);
namePosition = GetTZName(name.ToArray(), namePosition); namePosition = GetTZName(name, namePosition);
destLen = namePosition; destLen = namePosition;
} }
@@ -507,7 +502,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
if (name[namePosition] == '\0') if (name[namePosition] == '\0')
{ {
name = TimeZoneDefaultRule.ToCharArray(); name = TimeZoneDefaultRule;
namePosition = 0; namePosition = 0;
} }
@@ -515,7 +510,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
namePosition++; namePosition++;
bool IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule start); bool IsRuleValid = GetRule(name, ref namePosition, out Rule start);
if (!IsRuleValid) if (!IsRuleValid)
{ {
return false; return false;
@@ -526,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule end); IsRuleValid = GetRule(name, ref namePosition, out Rule end);
if (!IsRuleValid) if (!IsRuleValid)
{ {
return false; return false;
@@ -738,7 +733,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
charsPosition += stdLen; charsPosition += stdLen;
outRules.Chars[charsPosition++] = '\0'; outRules.Chars[charsPosition++] = 0;
if (destLen != 0) if (destLen != 0)
{ {
@@ -746,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
outRules.Chars[charsPosition + i] = destName[i]; outRules.Chars[charsPosition + i] = destName[i];
} }
outRules.Chars[charsPosition + destLen] = '\0'; outRules.Chars[charsPosition + destLen] = 0;
} }
return true; return true;
@@ -882,20 +877,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
} }
internal static bool ParsePosixName(string name, out TimeZoneRule outRules) internal static bool ParsePosixName(string name, ref TimeZoneRule outRules)
{ {
return ParsePosixName(name.ToCharArray(), out outRules, false); return ParsePosixName(Encoding.ASCII.GetBytes(name), ref outRules, false);
} }
internal static bool ParseTimeZoneBinary(out TimeZoneRule outRules, Stream inputData) internal static bool ParseTimeZoneBinary(ref TimeZoneRule outRules, Stream inputData)
{ {
outRules = new TimeZoneRule outRules = new TimeZoneRule();
{
Ats = new long[TzMaxTimes],
Types = new byte[TzMaxTimes],
Ttis = new TimeTypeInfo[TzMaxTypes],
Chars = new char[TzCharsArraySize]
};
BinaryReader reader = new BinaryReader(inputData); BinaryReader reader = new BinaryReader(inputData);
@@ -1020,10 +1009,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
outRules.Ttis[i] = ttis; outRules.Ttis[i] = ttis;
} }
Encoding.ASCII.GetChars(p[..outRules.CharCount].ToArray()).CopyTo(outRules.Chars.AsSpan()); p[..outRules.CharCount].CopyTo(outRules.Chars);
p = p[outRules.CharCount..]; p = p[outRules.CharCount..];
outRules.Chars[outRules.CharCount] = '\0'; outRules.Chars[outRules.CharCount] = 0;
for (int i = 0; i < outRules.TypeCount; i++) for (int i = 0; i < outRules.TypeCount; i++)
{ {
@@ -1077,27 +1066,30 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
char[] tempName = new char[TzNameMax + 1]; byte[] tempName = new byte[TzNameMax + 1];
Array.Copy(workBuffer, position, tempName, 0, nRead); Array.Copy(workBuffer, position, tempName, 0, nRead);
if (nRead > 2 && tempName[0] == '\n' && tempName[nRead - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes) if (nRead > 2 && tempName[0] == '\n' && tempName[nRead - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes)
{ {
tempName[nRead - 1] = '\0'; tempName[nRead - 1] = 0;
char[] name = new char[TzNameMax]; byte[] name = new byte[TzNameMax];
Array.Copy(tempName, 1, name, 0, nRead - 1); Array.Copy(tempName, 1, name, 0, nRead - 1);
if (ParsePosixName(name, out TimeZoneRule tempRules, false)) Box<TimeZoneRule> tempRulesBox = new Box<TimeZoneRule>();
ref TimeZoneRule tempRules = ref tempRulesBox.Data;
if (ParsePosixName(name, ref tempRulesBox.Data, false))
{ {
int abbreviationCount = 0; int abbreviationCount = 0;
charCount = outRules.CharCount; charCount = outRules.CharCount;
Span<char> chars = outRules.Chars; Span<byte> chars = outRules.Chars;
for (int i = 0; i < tempRules.TypeCount; i++) for (int i = 0; i < tempRules.TypeCount; i++)
{ {
ReadOnlySpan<char> tempChars = tempRules.Chars; ReadOnlySpan<byte> tempChars = tempRules.Chars;
ReadOnlySpan<char> tempAbbreviation = tempChars[tempRules.Ttis[i].AbbreviationListIndex..]; ReadOnlySpan<byte> tempAbbreviation = tempChars[tempRules.Ttis[i].AbbreviationListIndex..];
int j; int j;
@@ -1175,7 +1167,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
for (int i = 1; i < outRules.TimeCount; i++) for (int i = 1; i < outRules.TimeCount; i++)
{ {
if (TimeTypeEquals(outRules, outRules.Types[i], outRules.Types[0]) && DifferByRepeat(outRules.Ats[i], outRules.Ats[0])) if (TimeTypeEquals(in outRules, outRules.Types[i], outRules.Types[0]) && DifferByRepeat(outRules.Ats[i], outRules.Ats[0]))
{ {
outRules.GoBack = true; outRules.GoBack = true;
break; break;
@@ -1184,7 +1176,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
for (int i = outRules.TimeCount - 2; i >= 0; i--) for (int i = outRules.TimeCount - 2; i >= 0; i--)
{ {
if (TimeTypeEquals(outRules, outRules.Types[outRules.TimeCount - 1], outRules.Types[i]) && DifferByRepeat(outRules.Ats[outRules.TimeCount - 1], outRules.Ats[i])) if (TimeTypeEquals(in outRules, outRules.Types[outRules.TimeCount - 1], outRules.Types[i]) && DifferByRepeat(outRules.Ats[outRules.TimeCount - 1], outRules.Ats[i]))
{ {
outRules.GoAhead = true; outRules.GoAhead = true;
break; break;
@@ -1259,10 +1251,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
long remainingSeconds = time % SecondsPerDay; long remainingSeconds = time % SecondsPerDay;
calendarTime = new CalendarTimeInternal(); calendarTime = new CalendarTimeInternal();
calendarAdditionalInfo = new CalendarAdditionalInfo() calendarAdditionalInfo = new CalendarAdditionalInfo();
{
TimezoneName = new char[8]
};
while (timeDays < 0 || timeDays >= YearLengths[IsLeap((int)year)]) while (timeDays < 0 || timeDays >= YearLengths[IsLeap((int)year)])
{ {
@@ -1353,13 +1342,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return 0; return 0;
} }
private static ResultCode ToCalendarTimeInternal(TimeZoneRule rules, long time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo) private static ResultCode ToCalendarTimeInternal(in TimeZoneRule rules, long time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo)
{ {
calendarTime = new CalendarTimeInternal(); calendarTime = new CalendarTimeInternal();
calendarAdditionalInfo = new CalendarAdditionalInfo() calendarAdditionalInfo = new CalendarAdditionalInfo();
{
TimezoneName = new char[8]
};
ResultCode result; ResultCode result;
@@ -1398,7 +1384,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return ResultCode.TimeNotFound; return ResultCode.TimeNotFound;
} }
result = ToCalendarTimeInternal(rules, newTime, out calendarTime, out calendarAdditionalInfo); result = ToCalendarTimeInternal(in rules, newTime, out calendarTime, out calendarAdditionalInfo);
if (result != 0) if (result != 0)
{ {
return result; return result;
@@ -1450,17 +1436,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
calendarAdditionalInfo.IsDaySavingTime = rules.Ttis[ttiIndex].IsDaySavingTime; calendarAdditionalInfo.IsDaySavingTime = rules.Ttis[ttiIndex].IsDaySavingTime;
ReadOnlySpan<char> timeZoneAbbreviation = rules.Chars.AsSpan()[rules.Ttis[ttiIndex].AbbreviationListIndex..]; ReadOnlySpan<byte> timeZoneAbbreviation = rules.Chars[rules.Ttis[ttiIndex].AbbreviationListIndex..];
int timeZoneSize = Math.Min(StringUtils.LengthCstr(timeZoneAbbreviation), 8); int timeZoneSize = Math.Min(StringUtils.LengthCstr(timeZoneAbbreviation), 8);
timeZoneAbbreviation[..timeZoneSize].CopyTo(calendarAdditionalInfo.TimezoneName.AsSpan()); timeZoneAbbreviation[..timeZoneSize].CopyTo(calendarAdditionalInfo.TimezoneName.ToSpan());
} }
return result; return result;
} }
private static ResultCode ToPosixTimeInternal(TimeZoneRule rules, CalendarTimeInternal calendarTime, out long posixTime) private static ResultCode ToPosixTimeInternal(in TimeZoneRule rules, CalendarTimeInternal calendarTime, out long posixTime)
{ {
posixTime = 0; posixTime = 0;
@@ -1604,7 +1590,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int direction; int direction;
ResultCode result = ToCalendarTimeInternal(rules, pivot, out CalendarTimeInternal candidateCalendarTime, out _); ResultCode result = ToCalendarTimeInternal(in rules, pivot, out CalendarTimeInternal candidateCalendarTime, out _);
if (result != 0) if (result != 0)
{ {
if (pivot > 0) if (pivot > 0)
@@ -1675,9 +1661,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return ResultCode.Success; return ResultCode.Success;
} }
internal static ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar) internal static ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar)
{ {
ResultCode result = ToCalendarTimeInternal(rules, time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo); ResultCode result = ToCalendarTimeInternal(in rules, time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo);
calendar = new CalendarInfo() calendar = new CalendarInfo()
{ {
@@ -1697,7 +1683,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result; return result;
} }
internal static ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime) internal static ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
{ {
CalendarTimeInternal calendarTimeInternal = new CalendarTimeInternal() CalendarTimeInternal calendarTimeInternal = new CalendarTimeInternal()
{ {
@@ -1710,7 +1696,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
Second = calendarTime.Second Second = calendarTime.Second
}; };
return ToPosixTimeInternal(rules, calendarTimeInternal, out posixTime); return ToPosixTimeInternal(in rules, calendarTimeInternal, out posixTime);
} }
} }
} }

View File

@@ -16,7 +16,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; using TimeZoneRuleBox = Ryujinx.Common.Memory.Box<Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule>;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
@@ -149,7 +149,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
continue; continue;
} }
TimeZone.ParseTimeZoneBinary(out TimeZoneRule tzRule, tzif.Get.AsStream()); TimeZoneRuleBox tzRuleBox = new TimeZoneRuleBox();
ref TimeZoneRule tzRule = ref tzRuleBox.Data;
TimeZone.ParseTimeZoneBinary(ref tzRule, tzif.Get.AsStream());
TimeTypeInfo ttInfo; TimeTypeInfo ttInfo;
if (tzRule.TimeCount > 0) // Find the current transition period if (tzRule.TimeCount > 0) // Find the current transition period
@@ -174,10 +178,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
continue; continue;
} }
var abbrStart = tzRule.Chars.AsSpan(ttInfo.AbbreviationListIndex); var abbrStart = tzRule.Chars[ttInfo.AbbreviationListIndex..];
int abbrEnd = abbrStart.IndexOf('\0'); int abbrEnd = abbrStart.IndexOf((byte)0);
outList.Add((ttInfo.GmtOffset, locName, abbrStart.Slice(0, abbrEnd).ToString())); outList.Add((ttInfo.GmtOffset, locName, abbrStart[..abbrEnd].ToString()));
} }
} }
@@ -276,15 +280,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return (ResultCode)result.Value; return (ResultCode)result.Value;
} }
internal ResultCode LoadTimeZoneRule(out TimeZoneRule outRules, string locationName) internal ResultCode LoadTimeZoneRule(ref TimeZoneRule rules, string locationName)
{ {
outRules = new TimeZoneRule rules = default;
{
Ats = new long[TzMaxTimes],
Types = new byte[TzMaxTimes],
Ttis = new TimeTypeInfo[TzMaxTypes],
Chars = new char[TzCharsArraySize]
};
if (!HasTimeZoneBinaryTitle()) if (!HasTimeZoneBinaryTitle())
{ {
@@ -295,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
if (result == ResultCode.Success) if (result == ResultCode.Success)
{ {
result = Manager.ParseTimeZoneRuleBinary(out outRules, timeZoneBinaryStream); result = Manager.ParseTimeZoneRuleBinary(ref rules, timeZoneBinaryStream);
ncaFile.Dispose(); ncaFile.Dispose();
} }

View File

@@ -1,14 +1,14 @@
using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System.IO; using System.IO;
using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
class TimeZoneManager class TimeZoneManager
{ {
private bool _isInitialized; private bool _isInitialized;
private TimeZoneRule _myRules; private Box<TimeZoneRule> _myRules;
private string _deviceLocationName; private string _deviceLocationName;
private UInt128 _timeZoneRuleVersion; private UInt128 _timeZoneRuleVersion;
private uint _totalLocationNameCount; private uint _totalLocationNameCount;
@@ -21,15 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
_deviceLocationName = "UTC"; _deviceLocationName = "UTC";
_timeZoneRuleVersion = new UInt128(); _timeZoneRuleVersion = new UInt128();
_lock = new object(); _lock = new object();
_myRules = new Box<TimeZoneRule>();
// Empty rules
_myRules = new TimeZoneRule
{
Ats = new long[TzMaxTimes],
Types = new byte[TzMaxTimes],
Ttis = new TimeTypeInfo[TzMaxTypes],
Chars = new char[TzCharsArraySize]
};
_timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom(); _timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom();
} }
@@ -78,7 +70,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
lock (_lock) lock (_lock)
{ {
bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out TimeZoneRule rules, timeZoneBinaryStream); Box<TimeZoneRule> rules = new Box<TimeZoneRule>();
bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref rules.Data, timeZoneBinaryStream);
if (timeZoneConversionSuccess) if (timeZoneConversionSuccess)
{ {
@@ -154,13 +148,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result; return result;
} }
public ResultCode ParseTimeZoneRuleBinary(out TimeZoneRule outRules, Stream timeZoneBinaryStream) public ResultCode ParseTimeZoneRuleBinary(ref TimeZoneRule outRules, Stream timeZoneBinaryStream)
{ {
ResultCode result = ResultCode.Success; ResultCode result = ResultCode.Success;
lock (_lock) lock (_lock)
{ {
bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out outRules, timeZoneBinaryStream); bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref outRules, timeZoneBinaryStream);
if (!timeZoneConversionSuccess) if (!timeZoneConversionSuccess)
{ {
@@ -208,7 +202,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
if (_isInitialized) if (_isInitialized)
{ {
result = ToCalendarTime(_myRules, time, out calendar); result = ToCalendarTime(in _myRules.Data, time, out calendar);
} }
else else
{ {
@@ -220,13 +214,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result; return result;
} }
public ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar) public ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar)
{ {
ResultCode result; ResultCode result;
lock (_lock) lock (_lock)
{ {
result = TimeZone.ToCalendarTime(rules, time, out calendar); result = TimeZone.ToCalendarTime(in rules, time, out calendar);
} }
return result; return result;
@@ -240,7 +234,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
if (_isInitialized) if (_isInitialized)
{ {
result = ToPosixTime(_myRules, calendarTime, out posixTime); result = ToPosixTime(in _myRules.Data, calendarTime, out posixTime);
} }
else else
{ {
@@ -252,13 +246,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result; return result;
} }
public ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime) public ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
{ {
ResultCode result; ResultCode result;
lock (_lock) lock (_lock)
{ {
result = TimeZone.ToPosixTime(rules, calendarTime, out posixTime); result = TimeZone.ToPosixTime(in rules, calendarTime, out posixTime);
} }
return result; return result;

View File

@@ -1,4 +1,5 @@
using System.Runtime.InteropServices; using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
@@ -8,14 +9,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public uint DayOfWeek; public uint DayOfWeek;
public uint DayOfYear; public uint DayOfYear;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public Array8<byte> TimezoneName;
public char[] TimezoneName;
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsDaySavingTime; public bool IsDaySavingTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public Array3<byte> Padding;
public char[] Padding;
public int GmtOffset; public int GmtOffset;
} }

View File

@@ -1,17 +1,19 @@
using System.Runtime.InteropServices; using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
[StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 4)]
struct TimeTypeInfo public struct TimeTypeInfo
{ {
public const int Size = 0x10;
public int GmtOffset; public int GmtOffset;
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsDaySavingTime; public bool IsDaySavingTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public Array3<byte> Padding1;
public char[] Padding1;
public int AbbreviationListIndex; public int AbbreviationListIndex;
@@ -21,7 +23,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsGMT; public bool IsGMT;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public ushort Padding2;
public char[] Padding2;
} }
} }

View File

@@ -1,9 +1,11 @@
using System.Runtime.InteropServices; using Ryujinx.Common.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)]
struct TimeZoneRule public struct TimeZoneRule
{ {
public const int TzMaxTypes = 128; public const int TzMaxTypes = 128;
public const int TzMaxChars = 50; public const int TzMaxChars = 50;
@@ -22,17 +24,32 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool GoAhead; public bool GoAhead;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] [StructLayout(LayoutKind.Sequential, Size = sizeof(long) * TzMaxTimes)]
public long[] Ats; private struct AtsStorageStruct { }
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] private AtsStorageStruct _ats;
public byte[] Types;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)] public Span<long> Ats => SpanHelpers.AsSpan<AtsStorageStruct, long>(ref _ats);
public TimeTypeInfo[] Ttis;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)] [StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzMaxTimes)]
public char[] Chars; private struct TypesStorageStruct { }
private TypesStorageStruct _types;
public Span<byte> Types => SpanHelpers.AsByteSpan(ref _types);
[StructLayout(LayoutKind.Sequential, Size = TimeTypeInfo.Size * TzMaxTypes)]
private struct TimeTypeInfoStorageStruct { }
private TimeTypeInfoStorageStruct _ttis;
public Span<TimeTypeInfo> Ttis => SpanHelpers.AsSpan<TimeTypeInfoStorageStruct, TimeTypeInfo>(ref _ttis);
[StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzCharsArraySize)]
private struct CharsStorageStruct { }
private CharsStorageStruct _chars;
public Span<byte> Chars => SpanHelpers.AsByteSpan(ref _chars);
public int DefaultType; public int DefaultType;
} }

View File

@@ -128,7 +128,7 @@ namespace Ryujinx.HLE.Utilities
} }
} }
public static int CompareCStr(ReadOnlySpan<char> s1, ReadOnlySpan<char> s2) public static int CompareCStr(ReadOnlySpan<byte> s1, ReadOnlySpan<byte> s2)
{ {
int s1Index = 0; int s1Index = 0;
int s2Index = 0; int s2Index = 0;
@@ -142,11 +142,11 @@ namespace Ryujinx.HLE.Utilities
return s2[s2Index] - s1[s1Index]; return s2[s2Index] - s1[s1Index];
} }
public static int LengthCstr(ReadOnlySpan<char> s) public static int LengthCstr(ReadOnlySpan<byte> s)
{ {
int i = 0; int i = 0;
while (s[i] != '\0') while (s[i] != 0)
{ {
i++; i++;
} }

View File

@@ -227,6 +227,8 @@ namespace Ryujinx.Memory.Tracking
// Look up the virtual region using the region list. // Look up the virtual region using the region list.
// Signal up the chain to relevant handles. // Signal up the chain to relevant handles.
bool shouldThrow = false;
lock (TrackingLock) lock (TrackingLock)
{ {
ref var overlaps = ref ThreadStaticArray<VirtualRegion>.Get(); ref var overlaps = ref ThreadStaticArray<VirtualRegion>.Get();
@@ -235,19 +237,18 @@ namespace Ryujinx.Memory.Tracking
if (count == 0 && !precise) if (count == 0 && !precise)
{ {
if (!_memoryManager.IsMapped(address)) if (_memoryManager.IsMapped(address))
{ {
_invalidAccessHandler?.Invoke(address);
// We can't continue - it's impossible to remove protection from the page.
// Even if the access handler wants us to continue, we wouldn't be able to.
throw new InvalidMemoryRegionException();
}
_memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite); _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite);
return false; // We can't handle this - it's probably a real invalid access. return false; // We can't handle this - it's probably a real invalid access.
} }
else
{
shouldThrow = true;
}
}
else
{
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
VirtualRegion region = overlaps[i]; VirtualRegion region = overlaps[i];
@@ -262,6 +263,16 @@ namespace Ryujinx.Memory.Tracking
} }
} }
} }
}
if (shouldThrow)
{
_invalidAccessHandler?.Invoke(address);
// We can't continue - it's impossible to remove protection from the page.
// Even if the access handler wants us to continue, we wouldn't be able to.
throw new InvalidMemoryRegionException();
}
return true; return true;
} }

View File

@@ -24,6 +24,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" /> <ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" /> <ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" /> <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
<ProjectReference Include="..\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj" /> <ProjectReference Include="..\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" /> <ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />

View File

@@ -0,0 +1,18 @@
using NUnit.Framework;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using System.Runtime.CompilerServices;
namespace Ryujinx.Tests.Time
{
internal class TimeZoneRuleTests
{
class EffectInfoParameterTests
{
[Test]
public void EnsureTypeSize()
{
Assert.AreEqual(0x4000, Unsafe.SizeOf<TimeZoneRule>());
}
}
}
}