Improvements to input and input configuration in the GUI. (#849)

* Improvements to input and input configuration in the GUI

* Requested changes

* nits

* more nits
This commit is contained in:
Xpl0itR 2020-05-03 03:00:53 +01:00 committed by GitHub
parent 5f3558fd51
commit 538fba826b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 5883 additions and 2511 deletions

View File

@ -4,9 +4,7 @@ using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.Configuration.System;
using Ryujinx.Configuration.Hid;
using Ryujinx.Configuration.Ui;
using Ryujinx.UI.Input;
namespace Ryujinx.Configuration
{
@ -15,7 +13,7 @@ namespace Ryujinx.Configuration
/// <summary>
/// The current version of the file format
/// </summary>
public const int CurrentVersion = 5;
public const int CurrentVersion = 6;
public int Version { get; set; }
@ -129,11 +127,6 @@ namespace Ryujinx.Configuration
/// </summary>
public bool IgnoreMissingServices { get; set; }
/// <summary>
/// The primary controller's type
/// </summary>
public ControllerType ControllerType { get; set; }
/// <summary>
/// Used to toggle columns in the GUI
/// </summary>
@ -162,12 +155,12 @@ namespace Ryujinx.Configuration
/// <summary>
/// Keyboard control bindings
/// </summary>
public NpadKeyboard KeyboardControls { get; set; }
public List<KeyboardConfig> KeyboardConfig { get; set; }
/// <summary>
/// Controller control bindings
/// </summary>
public NpadController JoystickControls { get; set; }
public List<ControllerConfig> ControllerConfig { get; set; }
/// <summary>
/// Loads a configuration file from disk

View File

@ -1,10 +1,9 @@
using Ryujinx.Common;
using Ryujinx.Common;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using Ryujinx.Configuration.Hid;
using Ryujinx.Configuration.System;
using Ryujinx.Configuration.Ui;
using Ryujinx.UI.Input;
using System;
using System.Collections.Generic;
@ -159,7 +158,7 @@ namespace Ryujinx.Configuration
public ReactiveObject<string> TimeZone { get; private set; }
/// <summary>
/// System Time Offset in seconds
/// System Time Offset in Seconds
/// </summary>
public ReactiveObject<long> SystemTimeOffset { get; private set; }
@ -207,32 +206,22 @@ namespace Ryujinx.Configuration
/// </summary>
public class HidSection
{
/// <summary>
/// The primary controller's type
/// </summary>
public ReactiveObject<ControllerType> ControllerType { get; private set; }
/// <summary>
/// Enable or disable keyboard support (Independent from controllers binding)
/// </summary>
public ReactiveObject<bool> EnableKeyboard { get; private set; }
/// <summary>
/// Keyboard control bindings
/// Input device configuration.
/// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
/// TODO: Implement a ReactiveList class.
/// </summary>
public ReactiveObject<NpadKeyboard> KeyboardControls { get; private set; }
/// <summary>
/// Controller control bindings
/// </summary>
public ReactiveObject<NpadController> JoystickControls { get; private set; }
public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }
public HidSection()
{
ControllerType = new ReactiveObject<ControllerType>();
EnableKeyboard = new ReactiveObject<bool>();
KeyboardControls = new ReactiveObject<NpadKeyboard>();
JoystickControls = new ReactiveObject<NpadController>();
EnableKeyboard = new ReactiveObject<bool>();
InputConfig = new ReactiveObject<List<InputConfig>>();
}
}
@ -311,6 +300,21 @@ namespace Ryujinx.Configuration
public ConfigurationFileFormat ToFileFormat()
{
List<ControllerConfig> controllerConfigList = new List<ControllerConfig>();
List<KeyboardConfig> keyboardConfigList = new List<KeyboardConfig>();
foreach (InputConfig inputConfig in Hid.InputConfig.Value)
{
if (inputConfig is ControllerConfig controllerConfig)
{
controllerConfigList.Add(controllerConfig);
}
else if (inputConfig is KeyboardConfig keyboardConfig)
{
keyboardConfigList.Add(keyboardConfig);
}
}
ConfigurationFileFormat configurationFile = new ConfigurationFileFormat
{
Version = ConfigurationFileFormat.CurrentVersion,
@ -336,7 +340,6 @@ namespace Ryujinx.Configuration
EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
FsGlobalAccessLogMode = System.FsGlobalAccessLogMode,
IgnoreMissingServices = System.IgnoreMissingServices,
ControllerType = Hid.ControllerType,
GuiColumns = new GuiColumns()
{
FavColumn = Ui.GuiColumns.FavColumn,
@ -354,8 +357,8 @@ namespace Ryujinx.Configuration
EnableCustomTheme = Ui.EnableCustomTheme,
CustomThemePath = Ui.CustomThemePath,
EnableKeyboard = Hid.EnableKeyboard,
KeyboardControls = Hid.KeyboardControls,
JoystickControls = Hid.JoystickControls
KeyboardConfig = keyboardConfigList,
ControllerConfig = controllerConfigList
};
return configurationFile;
@ -385,7 +388,6 @@ namespace Ryujinx.Configuration
System.EnableFsIntegrityChecks.Value = true;
System.FsGlobalAccessLogMode.Value = 0;
System.IgnoreMissingServices.Value = false;
Hid.ControllerType.Value = ControllerType.Handheld;
Ui.GuiColumns.FavColumn.Value = true;
Ui.GuiColumns.IconColumn.Value = true;
Ui.GuiColumns.AppColumn.Value = true;
@ -401,73 +403,51 @@ namespace Ryujinx.Configuration
Ui.CustomThemePath.Value = "";
Hid.EnableKeyboard.Value = false;
Hid.KeyboardControls.Value = new NpadKeyboard
Hid.InputConfig.Value = new List<InputConfig>
{
LeftJoycon = new NpadKeyboardLeft
new KeyboardConfig
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
DPadUp = Key.Up,
DPadDown = Key.Down,
DPadLeft = Key.Left,
DPadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
},
RightJoycon = new NpadKeyboardRight
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
}
};
Hid.JoystickControls.Value = new NpadController
{
Enabled = true,
Index = 0,
Deadzone = 0.05f,
TriggerThreshold = 0.5f,
LeftJoycon = new NpadControllerLeft
{
Stick = ControllerInputId.Axis0,
StickButton = ControllerInputId.Button8,
DPadUp = ControllerInputId.Hat0Up,
DPadDown = ControllerInputId.Hat0Down,
DPadLeft = ControllerInputId.Hat0Left,
DPadRight = ControllerInputId.Hat0Right,
ButtonMinus = ControllerInputId.Button6,
ButtonL = ControllerInputId.Button4,
ButtonZl = ControllerInputId.Axis2,
},
RightJoycon = new NpadControllerRight
{
Stick = ControllerInputId.Axis3,
StickButton = ControllerInputId.Button9,
ButtonA = ControllerInputId.Button1,
ButtonB = ControllerInputId.Button0,
ButtonX = ControllerInputId.Button3,
ButtonY = ControllerInputId.Button2,
ButtonPlus = ControllerInputId.Button7,
ButtonR = ControllerInputId.Button5,
ButtonZr = ControllerInputId.Axis5,
Index = 0,
ControllerType = ControllerType.JoyconPair,
PlayerIndex = PlayerIndex.Player1,
LeftJoycon = new NpadKeyboardLeft
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
DPadUp = Key.Up,
DPadDown = Key.Down,
DPadLeft = Key.Left,
DPadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Home,
ButtonSr = Key.End
},
RightJoycon = new NpadKeyboardRight
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.PageUp,
ButtonSr = Key.PageDown
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
}
}
};
}
@ -521,6 +501,71 @@ namespace Ryujinx.Configuration
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 6)
{
Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 6.");
configurationFileFormat.ControllerConfig = new List<ControllerConfig>();
configurationFileFormat.KeyboardConfig = new List<KeyboardConfig>{
new KeyboardConfig
{
Index = 0,
ControllerType = ControllerType.JoyconPair,
PlayerIndex = PlayerIndex.Player1,
LeftJoycon = new NpadKeyboardLeft
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
DPadUp = Key.Up,
DPadDown = Key.Down,
DPadLeft = Key.Left,
DPadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound
},
RightJoycon = new NpadKeyboardRight
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
}
}
};
configurationFileUpdated = true;
}
List<InputConfig> inputConfig = new List<InputConfig>();
foreach (ControllerConfig controllerConfig in configurationFileFormat.ControllerConfig)
{
inputConfig.Add(controllerConfig);
}
foreach (KeyboardConfig keyboardConfig in configurationFileFormat.KeyboardConfig)
{
inputConfig.Add(keyboardConfig);
}
Graphics.MaxAnisotropy.Value = configurationFileFormat.MaxAnisotropy;
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
@ -544,7 +589,6 @@ namespace Ryujinx.Configuration
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
Hid.ControllerType.Value = configurationFileFormat.ControllerType;
Ui.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn;
Ui.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn;
Ui.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn;
@ -559,14 +603,13 @@ namespace Ryujinx.Configuration
Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme;
Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath;
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
Hid.KeyboardControls.Value = configurationFileFormat.KeyboardControls;
Hid.JoystickControls.Value = configurationFileFormat.JoystickControls;
Hid.InputConfig.Value = inputConfig;
if (configurationFileUpdated)
{
ToFileFormat().SaveConfig(configurationFilePath);
Common.Logging.Logger.PrintWarning(LogClass.Application, "Configuration file is updated!");
Common.Logging.Logger.PrintWarning(LogClass.Application, "Configuration file has been updated!");
}
}

View File

@ -1,21 +1,16 @@
namespace Ryujinx.Common.Configuration.Hid
{
public class NpadController
public class ControllerConfig : InputConfig
{
/// <summary>
/// Enables or disables controller support
/// Controller Left Analog Stick Deadzone
/// </summary>
public bool Enabled { get; set; }
public float DeadzoneLeft { get; set; }
/// <summary>
/// Controller Device Index
/// Controller Right Analog Stick Deadzone
/// </summary>
public int Index { get; set; }
/// <summary>
/// Controller Analog Stick Deadzone
/// </summary>
public float Deadzone { get; set; }
public float DeadzoneRight { get; set; }
/// <summary>
/// Controller Trigger Threshold

View File

@ -40,6 +40,7 @@
Hat2Up,
Hat2Down,
Hat2Left,
Hat2Right
Hat2Right,
Unbound
}
}

View File

@ -1,11 +1,20 @@
namespace Ryujinx.Configuration.Hid
using System;
namespace Ryujinx.Common.Configuration.Hid
{
public enum ControllerType
[Flags]
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
public enum ControllerType : int
{
ProController,
Handheld,
NpadPair,
NpadLeft,
NpadRight
None,
ProController = 1 << 0,
Handheld = 1 << 1,
JoyconPair = 1 << 2,
JoyconLeft = 1 << 3,
JoyconRight = 1 << 4,
Invalid = 1 << 5,
Pokeball = 1 << 6,
SystemExternal = 1 << 29,
System = 1 << 30
}
}

View File

@ -0,0 +1,20 @@
namespace Ryujinx.Common.Configuration.Hid
{
public class InputConfig
{
/// <summary>
/// Controller Device Index
/// </summary>
public int Index { get; set; }
/// <summary>
/// Controller's Type
/// </summary>
public ControllerType ControllerType { get; set; }
/// <summary>
/// Player's Index for the controller
/// </summary>
public PlayerIndex PlayerIndex { get; set; }
}
}

View File

@ -148,6 +148,7 @@
Slash = 128,
BackSlash = 129,
NonUSBackSlash = 130,
LastKey = 131
LastKey = 131,
Unbound
}
}

View File

@ -0,0 +1,20 @@
namespace Ryujinx.Common.Configuration.Hid
{
public class KeyboardConfig : InputConfig
{
/// <summary>
/// Left JoyCon Keyboard Bindings
/// </summary>
public NpadKeyboardLeft LeftJoycon { get; set; }
/// <summary>
/// Right JoyCon Keyboard Bindings
/// </summary>
public NpadKeyboardRight RightJoycon { get; set; }
/// <summary>
/// Hotkey Keyboard Bindings
/// </summary>
public KeyboardHotkeys Hotkeys { get; set; }
}
}

View File

@ -1,4 +1,6 @@
namespace Ryujinx.Configuration.Hid
using Ryujinx.Configuration.Hid;
namespace Ryujinx.Common.Configuration.Hid
{
public struct KeyboardHotkeys
{

View File

@ -2,11 +2,16 @@
{
public struct NpadControllerLeft
{
public ControllerInputId Stick { get; set; }
public ControllerInputId StickX { get; set; }
public bool InvertStickX { get; set; }
public ControllerInputId StickY { get; set; }
public bool InvertStickY { get; set; }
public ControllerInputId StickButton { get; set; }
public ControllerInputId ButtonMinus { get; set; }
public ControllerInputId ButtonL { get; set; }
public ControllerInputId ButtonZl { get; set; }
public ControllerInputId ButtonSl { get; set; }
public ControllerInputId ButtonSr { get; set; }
public ControllerInputId DPadUp { get; set; }
public ControllerInputId DPadDown { get; set; }
public ControllerInputId DPadLeft { get; set; }

View File

@ -2,7 +2,10 @@
{
public struct NpadControllerRight
{
public ControllerInputId Stick { get; set; }
public ControllerInputId StickX { get; set; }
public bool InvertStickX { get; set; }
public ControllerInputId StickY { get; set; }
public bool InvertStickY { get; set; }
public ControllerInputId StickButton { get; set; }
public ControllerInputId ButtonA { get; set; }
public ControllerInputId ButtonB { get; set; }
@ -11,5 +14,7 @@
public ControllerInputId ButtonPlus { get; set; }
public ControllerInputId ButtonR { get; set; }
public ControllerInputId ButtonZr { get; set; }
public ControllerInputId ButtonSl { get; set; }
public ControllerInputId ButtonSr { get; set; }
}
}

View File

@ -1,20 +0,0 @@
namespace Ryujinx.UI.Input
{
public class NpadKeyboard
{
/// <summary>
/// Left JoyCon Keyboard Bindings
/// </summary>
public Configuration.Hid.NpadKeyboardLeft LeftJoycon { get; set; }
/// <summary>
/// Right JoyCon Keyboard Bindings
/// </summary>
public Configuration.Hid.NpadKeyboardRight RightJoycon { get; set; }
/// <summary>
/// Hotkey Keyboard Bindings
/// </summary>
public Configuration.Hid.KeyboardHotkeys Hotkeys { get; set; }
}
}

View File

@ -1,4 +1,6 @@
namespace Ryujinx.Configuration.Hid
using Ryujinx.Configuration.Hid;
namespace Ryujinx.Common.Configuration.Hid
{
public struct NpadKeyboardLeft
{
@ -14,5 +16,7 @@
public Key ButtonMinus { get; set; }
public Key ButtonL { get; set; }
public Key ButtonZl { get; set; }
public Key ButtonSl { get; set; }
public Key ButtonSr { get; set; }
}
}

View File

@ -1,4 +1,6 @@
namespace Ryujinx.Configuration.Hid
using Ryujinx.Configuration.Hid;
namespace Ryujinx.Common.Configuration.Hid
{
public struct NpadKeyboardRight
{
@ -14,5 +16,7 @@
public Key ButtonPlus { get; set; }
public Key ButtonR { get; set; }
public Key ButtonZr { get; set; }
public Key ButtonSl { get; set; }
public Key ButtonSr { get; set; }
}
}

View File

@ -0,0 +1,18 @@
namespace Ryujinx.Common.Configuration.Hid
{
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
public enum PlayerIndex : int
{
Player1 = 0,
Player2 = 1,
Player3 = 2,
Player4 = 3,
Player5 = 4,
Player6 = 5,
Player7 = 6,
Player8 = 7,
Handheld = 8,
Unknown = 9,
Auto = 10 // Shouldn't be used directly
}
}

View File

@ -7,16 +7,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public class Hid
{
private readonly Switch _device;
private long _hidMemoryAddress;
private readonly long _hidMemoryAddress;
internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetStructRef<HidSharedMemory>(_hidMemoryAddress);
internal const int SharedMemEntryCount = 17;
public DebugPadDevice DebugPad;
public TouchDevice Touchscreen;
public MouseDevice Mouse;
public TouchDevice Touchscreen;
public MouseDevice Mouse;
public KeyboardDevice Keyboard;
public NpadDevices Npads;
public NpadDevices Npads;
static Hid()
{
@ -48,7 +48,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public Hid(in Switch device, long sharedHidMemoryAddress)
{
_device = device;
_device = device;
_hidMemoryAddress = sharedHidMemoryAddress;
device.Memory.FillWithZeros(sharedHidMemoryAddress, Horizon.HidSize);
@ -56,26 +56,26 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public void InitDevices()
{
DebugPad = new DebugPadDevice(_device, true);
DebugPad = new DebugPadDevice(_device, true);
Touchscreen = new TouchDevice(_device, true);
Mouse = new MouseDevice(_device, false);
Keyboard = new KeyboardDevice(_device, false);
Npads = new NpadDevices(_device, true);
Mouse = new MouseDevice(_device, false);
Keyboard = new KeyboardDevice(_device, false);
Npads = new NpadDevices(_device, true);
}
public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
{
ControllerKeys result = 0;
result |= (leftStick.Dx < 0) ? ControllerKeys.LStickLeft : result;
result |= (leftStick.Dx < 0) ? ControllerKeys.LStickLeft : result;
result |= (leftStick.Dx > 0) ? ControllerKeys.LStickRight : result;
result |= (leftStick.Dy < 0) ? ControllerKeys.LStickDown : result;
result |= (leftStick.Dy > 0) ? ControllerKeys.LStickUp : result;
result |= (leftStick.Dy < 0) ? ControllerKeys.LStickDown : result;
result |= (leftStick.Dy > 0) ? ControllerKeys.LStickUp : result;
result |= (rightStick.Dx < 0) ? ControllerKeys.RStickLeft : result;
result |= (rightStick.Dx < 0) ? ControllerKeys.RStickLeft : result;
result |= (rightStick.Dx > 0) ? ControllerKeys.RStickRight : result;
result |= (rightStick.Dy < 0) ? ControllerKeys.RStickDown : result;
result |= (rightStick.Dy > 0) ? ControllerKeys.RStickUp : result;
result |= (rightStick.Dy < 0) ? ControllerKeys.RStickDown : result;
result |= (rightStick.Dy > 0) ? ControllerKeys.RStickUp : result;
return result;
}

View File

@ -1,6 +1,6 @@
using System;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Services.Hid
{
@ -9,14 +9,14 @@ namespace Ryujinx.HLE.HOS.Services.Hid
internal NpadJoyHoldType JoyHold = NpadJoyHoldType.Vertical;
internal bool SixAxisActive = false; // TODO: link to hidserver when implemented
enum FilterState
private enum FilterState
{
Unconfigured = 0,
Configured = 1,
Accepted = 2
Configured = 1,
Accepted = 2
}
struct NpadConfig
private struct NpadConfig
{
public ControllerType ConfiguredType;
public FilterState State;
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public ControllerType SupportedStyleSets
{
get { return _supportedStyleSets; }
get => _supportedStyleSets;
set
{
if (_supportedStyleSets != value) // Deal with spamming
@ -46,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public PlayerIndex PrimaryController { get; set; } = PlayerIndex.Unknown;
KEvent[] _styleSetUpdateEvents;
private KEvent[] _styleSetUpdateEvents;
static readonly Array3<BatteryCharge> _fullBattery;
private static readonly Array3<BatteryCharge> _fullBattery;
public NpadDevices(Switch device, bool active = true) : base(device, active)
{
@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
for (int i = 0; i < configs.Length; ++i)
{
PlayerIndex player = configs[i].Player;
PlayerIndex player = configs[i].Player;
ControllerType controllerType = configs[i].Type;
if (player > PlayerIndex.Handheld)
@ -87,7 +87,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
MatchControllers();
}
void MatchControllers()
private void MatchControllers()
{
PrimaryController = PlayerIndex.Unknown;
@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
return ref _styleSetUpdateEvents[(int)player];
}
void InitController(PlayerIndex player, ControllerType type)
private void InitController(PlayerIndex player, ControllerType type)
{
if (type == ControllerType.Handheld)
{
@ -155,13 +155,13 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// TODO: Allow customizing colors at config
NpadStateHeader defaultHeader = new NpadStateHeader
{
IsHalf = false,
SingleColorBody = NpadColor.BodyGray,
IsHalf = false,
SingleColorBody = NpadColor.BodyGray,
SingleColorButtons = NpadColor.ButtonGray,
LeftColorBody = NpadColor.BodyNeonBlue,
LeftColorButtons = NpadColor.ButtonGray,
RightColorBody = NpadColor.BodyNeonRed,
RightColorButtons = NpadColor.ButtonGray
LeftColorBody = NpadColor.BodyNeonBlue,
LeftColorButtons = NpadColor.ButtonGray,
RightColorBody = NpadColor.BodyNeonRed,
RightColorButtons = NpadColor.ButtonGray
};
controller.SystemProperties = NpadSystemProperties.PowerInfo0Connected |
@ -173,44 +173,44 @@ namespace Ryujinx.HLE.HOS.Services.Hid
switch (type)
{
case ControllerType.ProController:
defaultHeader.Type = ControllerType.ProController;
controller.DeviceType = DeviceType.FullKey;
defaultHeader.Type = ControllerType.ProController;
controller.DeviceType = DeviceType.FullKey;
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
NpadSystemProperties.PlusButtonCapability |
NpadSystemProperties.MinusButtonCapability;
break;
case ControllerType.Handheld:
defaultHeader.Type = ControllerType.Handheld;
controller.DeviceType = DeviceType.HandheldLeft |
defaultHeader.Type = ControllerType.Handheld;
controller.DeviceType = DeviceType.HandheldLeft |
DeviceType.HandheldRight;
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
NpadSystemProperties.PlusButtonCapability |
NpadSystemProperties.MinusButtonCapability;
break;
case ControllerType.JoyconPair:
defaultHeader.Type = ControllerType.JoyconPair;
controller.DeviceType = DeviceType.JoyLeft |
defaultHeader.Type = ControllerType.JoyconPair;
controller.DeviceType = DeviceType.JoyLeft |
DeviceType.JoyRight;
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
NpadSystemProperties.PlusButtonCapability |
NpadSystemProperties.MinusButtonCapability;
break;
case ControllerType.JoyconLeft:
defaultHeader.Type = ControllerType.JoyconLeft;
defaultHeader.IsHalf = true;
controller.DeviceType = DeviceType.JoyLeft;
defaultHeader.Type = ControllerType.JoyconLeft;
defaultHeader.IsHalf = true;
controller.DeviceType = DeviceType.JoyLeft;
controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
NpadSystemProperties.MinusButtonCapability;
break;
case ControllerType.JoyconRight:
defaultHeader.Type = ControllerType.JoyconRight;
defaultHeader.IsHalf = true;
controller.DeviceType = DeviceType.JoyRight;
defaultHeader.Type = ControllerType.JoyconRight;
defaultHeader.IsHalf = true;
controller.DeviceType = DeviceType.JoyRight;
controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
NpadSystemProperties.PlusButtonCapability;
break;
case ControllerType.Pokeball:
defaultHeader.Type = ControllerType.Pokeball;
defaultHeader.Type = ControllerType.Pokeball;
controller.DeviceType = DeviceType.Palma;
break;
}
@ -229,16 +229,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid
Logger.PrintInfo(LogClass.Hid, $"Connected ControllerType {type} to PlayerIndex {player}");
}
static NpadLayoutsIndex ControllerTypeToLayout(ControllerType controllerType)
private static NpadLayoutsIndex ControllerTypeToLayout(ControllerType controllerType)
=> controllerType switch
{
ControllerType.ProController => NpadLayoutsIndex.ProController,
ControllerType.Handheld => NpadLayoutsIndex.Handheld,
ControllerType.JoyconPair => NpadLayoutsIndex.JoyDual,
ControllerType.JoyconLeft => NpadLayoutsIndex.JoyLeft,
ControllerType.JoyconRight => NpadLayoutsIndex.JoyRight,
ControllerType.Pokeball => NpadLayoutsIndex.Pokeball,
_ => NpadLayoutsIndex.SystemExternal
ControllerType.Handheld => NpadLayoutsIndex.Handheld,
ControllerType.JoyconPair => NpadLayoutsIndex.JoyDual,
ControllerType.JoyconLeft => NpadLayoutsIndex.JoyLeft,
ControllerType.JoyconRight => NpadLayoutsIndex.JoyRight,
ControllerType.Pokeball => NpadLayoutsIndex.Pokeball,
_ => NpadLayoutsIndex.SystemExternal
};
public void SetGamepadsInput(params GamepadInput[] states)
@ -251,8 +251,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
}
}
void SetGamepadState(PlayerIndex player, ControllerKeys buttons,
JoystickPosition leftJoystick, JoystickPosition rightJoystick)
private void SetGamepadState(PlayerIndex player, ControllerKeys buttons,
JoystickPosition leftJoystick, JoystickPosition rightJoystick)
{
if (player == PlayerIndex.Auto)
{
@ -269,9 +269,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
return;
}
ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)player];
ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)player];
ref NpadLayout currentLayout = ref currentNpad.Layouts[(int)ControllerTypeToLayout(currentNpad.Header.Type)];
ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry];
ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry];
currentEntry.Buttons = buttons;
currentEntry.LStickX = leftJoystick.Dx;
@ -284,7 +284,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
mainLayout.Entries[(int)mainLayout.Header.LatestEntry] = currentEntry;
}
void UpdateAllEntries()
private void UpdateAllEntries()
{
ref Array10<ShMemNpad> controllers = ref _device.Hid.SharedMemory.Npads;
for (int i = 0; i < controllers.Length; ++i)
@ -296,9 +296,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
int currentIndex = UpdateEntriesHeader(ref currentLayout.Header, out int previousIndex);
ref NpadState currentEntry = ref currentLayout.Entries[currentIndex];
NpadState previousEntry = currentLayout.Entries[previousIndex];
NpadState previousEntry = currentLayout.Entries[previousIndex];
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
if (controllers[i].Header.Type == ControllerType.None)

View File

@ -2,7 +2,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
public struct ControllerConfig
{
public PlayerIndex Player;
public PlayerIndex Player;
public ControllerType Type;
}
}

View File

@ -2,8 +2,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
public struct GamepadInput
{
public PlayerIndex PlayerId;
public ControllerKeys Buttons;
public PlayerIndex PlayerId;
public ControllerKeys Buttons;
public JoystickPosition LStick;
public JoystickPosition RStick;
}

View File

@ -5,41 +5,41 @@ namespace Ryujinx.HLE.HOS.Services.Hid
[Flags]
public enum ControllerKeys : long
{
A = 1 << 0,
B = 1 << 1,
X = 1 << 2,
Y = 1 << 3,
LStick = 1 << 4,
RStick = 1 << 5,
L = 1 << 6,
R = 1 << 7,
Zl = 1 << 8,
Zr = 1 << 9,
Plus = 1 << 10,
Minus = 1 << 11,
DpadLeft = 1 << 12,
DpadUp = 1 << 13,
DpadRight = 1 << 14,
DpadDown = 1 << 15,
LStickLeft = 1 << 16,
LStickUp = 1 << 17,
A = 1 << 0,
B = 1 << 1,
X = 1 << 2,
Y = 1 << 3,
LStick = 1 << 4,
RStick = 1 << 5,
L = 1 << 6,
R = 1 << 7,
Zl = 1 << 8,
Zr = 1 << 9,
Plus = 1 << 10,
Minus = 1 << 11,
DpadLeft = 1 << 12,
DpadUp = 1 << 13,
DpadRight = 1 << 14,
DpadDown = 1 << 15,
LStickLeft = 1 << 16,
LStickUp = 1 << 17,
LStickRight = 1 << 18,
LStickDown = 1 << 19,
RStickLeft = 1 << 20,
RStickUp = 1 << 21,
LStickDown = 1 << 19,
RStickLeft = 1 << 20,
RStickUp = 1 << 21,
RStickRight = 1 << 22,
RStickDown = 1 << 23,
SlLeft = 1 << 24,
SrLeft = 1 << 25,
SlRight = 1 << 26,
SrRight = 1 << 27,
RStickDown = 1 << 23,
SlLeft = 1 << 24,
SrLeft = 1 << 25,
SlRight = 1 << 26,
SrRight = 1 << 27,
// Generic Catch-all
Up = DpadUp | LStickUp | RStickUp,
Down = DpadDown | LStickDown | RStickDown,
Left = DpadLeft | LStickLeft | RStickLeft,
Up = DpadUp | LStickUp | RStickUp,
Down = DpadDown | LStickDown | RStickDown,
Left = DpadLeft | LStickLeft | RStickLeft,
Right = DpadRight | LStickRight | RStickRight,
Sl = SlLeft | SlRight,
Sr = SrLeft | SrRight
Sl = SlLeft | SlRight,
Sr = SrLeft | SrRight
}
}

View File

@ -6,14 +6,14 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public enum ControllerType : int
{
None,
ProController = 1 << 0,
Handheld = 1 << 1,
JoyconPair = 1 << 2,
JoyconLeft = 1 << 3,
JoyconRight = 1 << 4,
Invalid = 1 << 5,
Pokeball = 1 << 6,
ProController = 1 << 0,
Handheld = 1 << 1,
JoyconPair = 1 << 2,
JoyconLeft = 1 << 3,
JoyconRight = 1 << 4,
Invalid = 1 << 5,
Pokeball = 1 << 6,
SystemExternal = 1 << 29,
System = 1 << 30
System = 1 << 30
}
}

View File

@ -2,12 +2,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
{
enum NpadLayoutsIndex : int
{
ProController = 0,
Handheld = 1,
JoyDual = 2,
JoyLeft = 3,
JoyRight = 4,
Pokeball = 5,
ProController = 0,
Handheld = 1,
JoyDual = 2,
JoyLeft = 3,
JoyRight = 4,
Pokeball = 5,
SystemExternal = 6
}
}

View File

@ -14,6 +14,6 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
public DeviceState State = DeviceState.Unavailable;
public PlayerIndex Handle;
public NpadIdType NpadIdType;
public NpadIdType NpadIdType;
}
}

View File

@ -1,5 +1,5 @@
{
"version": 5,
"version": 6,
"max_anisotropy": -1,
"graphics_shaders_dump_path": "",
"logging_enable_debug": false,
@ -22,7 +22,6 @@
"enable_fs_integrity_checks": true,
"fs_global_access_log_mode": 0,
"ignore_missing_services": false,
"controller_type": "Handheld",
"gui_columns": {
"fav_column": true,
"icon_column": true,
@ -39,65 +38,47 @@
"enable_custom_theme": false,
"custom_theme_path": "",
"enable_keyboard": false,
"keyboard_controls": {
"left_joycon": {
"stick_up": "W",
"stick_down": "S",
"stick_left": "A",
"stick_right": "D",
"stick_button": "F",
"dpad_up": "Up",
"dpad_down": "Down",
"dpad_left": "Left",
"dpad_right": "Right",
"button_minus": "Minus",
"button_l": "E",
"button_zl": "Q"
},
"right_joycon": {
"stick_up": "I",
"stick_down": "K",
"stick_left": "J",
"stick_right": "L",
"stick_button": "H",
"button_a": "Z",
"button_b": "X",
"button_x": "C",
"button_y": "V",
"button_plus": "Plus",
"button_r": "U",
"button_zr": "O"
},
"hotkeys": {
"toggle_vsync": "Tab"
"keyboard_config": [
{
"index": 0,
"controller_type": "JoyconPair",
"player_index": "Player1",
"left_joycon": {
"stick_up": "W",
"stick_down": "S",
"stick_left": "A",
"stick_right": "D",
"stick_button": "F",
"dpad_up": "Up",
"dpad_down": "Down",
"dpad_left": "Left",
"dpad_right": "Right",
"button_minus": "Minus",
"button_l": "E",
"button_zl": "Q",
"button_sl": "Unbound",
"button_sr": "Unbound"
},
"right_joycon": {
"stick_up": "I",
"stick_down": "K",
"stick_left": "J",
"stick_right": "L",
"stick_button": "H",
"button_a": "Z",
"button_b": "X",
"button_x": "C",
"button_y": "V",
"button_plus": "Plus",
"button_r": "U",
"button_zr": "O",
"button_sl": "Unbound",
"button_sr": "Unbound"
},
"hotkeys": {
"toggle_vsync": "Tab"
}
}
},
"joystick_controls": {
"enabled": true,
"index": 0,
"deadzone": 0.05,
"trigger_threshold": 0.5,
"left_joycon": {
"stick": "Axis0",
"stick_button": "Button8",
"button_minus": "Button6",
"button_l": "Button4",
"button_zl": "Axis2",
"dpad_up": "Hat0Up",
"dpad_down": "Hat0Down",
"dpad_left": "Hat0Left",
"dpad_right": "Hat0Right"
},
"right_joycon": {
"stick": "Axis3",
"stick_button": "Button9",
"button_a": "Button1",
"button_b": "Button0",
"button_x": "Button3",
"button_y": "Button2",
"button_plus": "Button7",
"button_r": "Button5",
"button_zr": "Axis5"
}
}
],
"controller_config": []
}

View File

@ -31,9 +31,10 @@
<ItemGroup>
<None Remove="Ui\AboutWindow.glade" />
<None Remove="Ui\assets\BlueCon.png" />
<None Remove="Ui\assets\ProCon.png" />
<None Remove="Ui\assets\RedCon.png" />
<None Remove="Ui\assets\JoyConLeft.svg" />
<None Remove="Ui\assets\JoyConPair.svg" />
<None Remove="Ui\assets\JoyConRight.svg" />
<None Remove="Ui\assets\ProCon.svg" />
<None Remove="Ui\assets\NCAIcon.png" />
<None Remove="Ui\assets\NROIcon.png" />
<None Remove="Ui\assets\NSOIcon.png" />
@ -41,21 +42,23 @@
<None Remove="Ui\assets\XCIIcon.png" />
<None Remove="Ui\assets\DiscordLogo.png" />
<None Remove="Ui\assets\GitHubLogo.png" />
<None Remove="Ui\assets\JoyCon.png" />
<None Remove="Ui\assets\PatreonLogo.png" />
<None Remove="Ui\assets\Icon.png" />
<None Remove="Ui\assets\TwitterLogo.png" />
<None Remove="Ui\ControllerWindow.glade" />
<None Remove="Ui\GameTableContextMenu.glade" />
<None Remove="Ui\MainWindow.glade" />
<None Remove="Ui\SwitchSettings.glade" />
<None Remove="Ui\ProfileDialog.glade" />
<None Remove="Ui\SettingsWindow.glade" />
<None Remove="Ui\TitleUpdateWindow.glade" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Ui\AboutWindow.glade" />
<EmbeddedResource Include="Ui\assets\BlueCon.png" />
<EmbeddedResource Include="Ui\assets\ProCon.png" />
<EmbeddedResource Include="Ui\assets\RedCon.png" />
<EmbeddedResource Include="Ui\assets\JoyConLeft.svg" />
<EmbeddedResource Include="Ui\assets\JoyConPair.svg" />
<EmbeddedResource Include="Ui\assets\JoyConRight.svg" />
<EmbeddedResource Include="Ui\assets\ProCon.svg" />
<EmbeddedResource Include="Ui\assets\NCAIcon.png" />
<EmbeddedResource Include="Ui\assets\NROIcon.png" />
<EmbeddedResource Include="Ui\assets\NSOIcon.png" />
@ -63,13 +66,14 @@
<EmbeddedResource Include="Ui\assets\XCIIcon.png" />
<EmbeddedResource Include="Ui\assets\DiscordLogo.png" />
<EmbeddedResource Include="Ui\assets\GitHubLogo.png" />
<EmbeddedResource Include="Ui\assets\JoyCon.png" />
<EmbeddedResource Include="Ui\assets\PatreonLogo.png" />
<EmbeddedResource Include="Ui\assets\Icon.png" />
<EmbeddedResource Include="Ui\assets\TwitterLogo.png" />
<EmbeddedResource Include="Ui\ControllerWindow.glade" />
<EmbeddedResource Include="Ui\GameTableContextMenu.glade" />
<EmbeddedResource Include="Ui\MainWindow.glade" />
<EmbeddedResource Include="Ui\SwitchSettings.glade" />
<EmbeddedResource Include="Ui\ProfileDialog.glade" />
<EmbeddedResource Include="Ui\SettingsWindow.glade" />
<EmbeddedResource Include="Ui\TitleUpdateWindow.glade" />
</ItemGroup>

View File

@ -12,7 +12,6 @@ namespace Ryujinx.Ui
{
#pragma warning disable CS0649
#pragma warning disable IDE0044
[GUI] Window _aboutWin;
[GUI] Label _versionText;
[GUI] Image _ryujinxLogo;
[GUI] Image _patreonLogo;
@ -28,7 +27,7 @@ namespace Ryujinx.Ui
{
builder.Autoconnect(this);
_aboutWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
_ryujinxLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png" , 100, 100);
_patreonLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.PatreonLogo.png", 30 , 30 );
_gitHubLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.GitHubLogo.png" , 30 , 30 );

View File

@ -413,7 +413,7 @@ namespace Ryujinx.Ui
Version = version,
TimePlayed = ConvertSecondsToReadableString(appMetadata.TimePlayed),
LastPlayed = appMetadata.LastPlayed,
FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1),
FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
Path = applicationPath,
SaveDataPath = saveDataPath,

View File

@ -0,0 +1,925 @@
using Gtk;
using OpenTK.Input;
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using Ryujinx.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using GUI = Gtk.Builder.ObjectAttribute;
using Key = Ryujinx.Configuration.Hid.Key;
namespace Ryujinx.Ui
{
public class ControllerWindow : Window
{
private PlayerIndex _playerIndex;
private InputConfig _inputConfig;
private bool _isWaitingForInput;
private VirtualFileSystem _virtualFileSystem;
#pragma warning disable CS0649, IDE0044
[GUI] Adjustment _controllerDeadzoneLeft;
[GUI] Adjustment _controllerDeadzoneRight;
[GUI] Adjustment _controllerTriggerThreshold;
[GUI] ComboBoxText _inputDevice;
[GUI] ComboBoxText _profile;
[GUI] ToggleButton _refreshInputDevicesButton;
[GUI] Box _settingsBox;
[GUI] Grid _leftStickKeyboard;
[GUI] Grid _leftStickController;
[GUI] Box _deadZoneLeftBox;
[GUI] Grid _rightStickKeyboard;
[GUI] Grid _rightStickController;
[GUI] Box _deadZoneRightBox;
[GUI] Grid _leftSideTriggerBox;
[GUI] Grid _rightSideTriggerBox;
[GUI] Box _triggerThresholdBox;
[GUI] ComboBoxText _controllerType;
[GUI] ToggleButton _lStickX;
[GUI] CheckButton _invertLStickX;
[GUI] ToggleButton _lStickY;
[GUI] CheckButton _invertLStickY;
[GUI] ToggleButton _lStickUp;
[GUI] ToggleButton _lStickDown;
[GUI] ToggleButton _lStickLeft;
[GUI] ToggleButton _lStickRight;
[GUI] ToggleButton _lStickButton;
[GUI] ToggleButton _dpadUp;
[GUI] ToggleButton _dpadDown;
[GUI] ToggleButton _dpadLeft;
[GUI] ToggleButton _dpadRight;
[GUI] ToggleButton _minus;
[GUI] ToggleButton _l;
[GUI] ToggleButton _zL;
[GUI] ToggleButton _rStickX;
[GUI] CheckButton _invertRStickX;
[GUI] ToggleButton _rStickY;
[GUI] CheckButton _invertRStickY;
[GUI] ToggleButton _rStickUp;
[GUI] ToggleButton _rStickDown;
[GUI] ToggleButton _rStickLeft;
[GUI] ToggleButton _rStickRight;
[GUI] ToggleButton _rStickButton;
[GUI] ToggleButton _a;
[GUI] ToggleButton _b;
[GUI] ToggleButton _x;
[GUI] ToggleButton _y;
[GUI] ToggleButton _plus;
[GUI] ToggleButton _r;
[GUI] ToggleButton _zR;
[GUI] ToggleButton _lSl;
[GUI] ToggleButton _lSr;
[GUI] ToggleButton _rSl;
[GUI] ToggleButton _rSr;
[GUI] Image _controllerImage;
#pragma warning restore CS0649, IDE0044
public ControllerWindow(PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.ControllerWindow.glade"), controllerId, virtualFileSystem) { }
private ControllerWindow(Builder builder, PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : base(builder.GetObject("_controllerWin").Handle)
{
builder.Autoconnect(this);
this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
_playerIndex = controllerId;
_virtualFileSystem = virtualFileSystem;
_inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerIndex);
//Bind Events
_lStickX.Clicked += Button_Pressed;
_lStickY.Clicked += Button_Pressed;
_lStickUp.Clicked += Button_Pressed;
_lStickDown.Clicked += Button_Pressed;
_lStickLeft.Clicked += Button_Pressed;
_lStickRight.Clicked += Button_Pressed;
_lStickButton.Clicked += Button_Pressed;
_dpadUp.Clicked += Button_Pressed;
_dpadDown.Clicked += Button_Pressed;
_dpadLeft.Clicked += Button_Pressed;
_dpadRight.Clicked += Button_Pressed;
_minus.Clicked += Button_Pressed;
_l.Clicked += Button_Pressed;
_zL.Clicked += Button_Pressed;
_lSl.Clicked += Button_Pressed;
_lSr.Clicked += Button_Pressed;
_rStickX.Clicked += Button_Pressed;
_rStickY.Clicked += Button_Pressed;
_rStickUp.Clicked += Button_Pressed;
_rStickDown.Clicked += Button_Pressed;
_rStickLeft.Clicked += Button_Pressed;
_rStickRight.Clicked += Button_Pressed;
_rStickButton.Clicked += Button_Pressed;
_a.Clicked += Button_Pressed;
_b.Clicked += Button_Pressed;
_x.Clicked += Button_Pressed;
_y.Clicked += Button_Pressed;
_plus.Clicked += Button_Pressed;
_r.Clicked += Button_Pressed;
_zR.Clicked += Button_Pressed;
_rSl.Clicked += Button_Pressed;
_rSr.Clicked += Button_Pressed;
// Setup current values
UpdateInputDeviceList();
SetAvailableOptions();
ClearValues();
if (_inputDevice.ActiveId != null) SetCurrentValues();
}
private void UpdateInputDeviceList()
{
_inputDevice.RemoveAll();
_inputDevice.Append("disabled", "Disabled");
_inputDevice.SetActiveId("disabled");
for (int i = 0; i < 20; i++)
{
if (Keyboard.GetState(i).IsConnected)
_inputDevice.Append($"keyboard/{i}", $"Keyboard/{i}");
if (GamePad.GetState(i).IsConnected)
_inputDevice.Append($"controller/{i}", $"Controller/{i} ({GamePad.GetName(i)})");
}
switch (_inputConfig)
{
case KeyboardConfig keyboard:
_inputDevice.SetActiveId($"keyboard/{keyboard.Index}");
break;
case ControllerConfig controller:
_inputDevice.SetActiveId($"controller/{controller.Index}");
break;
}
}
private void SetAvailableOptions()
{
if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("keyboard"))
{
this.ShowAll();
_leftStickController.Hide();
_rightStickController.Hide();
_deadZoneLeftBox.Hide();
_deadZoneRightBox.Hide();
_triggerThresholdBox.Hide();
}
else if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("controller"))
{
this.ShowAll();
_leftStickKeyboard.Hide();
_rightStickKeyboard.Hide();
}
else
{
_settingsBox.Hide();
}
ClearValues();
}
private void SetCurrentValues()
{
SetControllerSpecificFields();
SetProfiles();
if (_inputDevice.ActiveId.StartsWith("keyboard") && _inputConfig is KeyboardConfig)
{
SetValues(_inputConfig);
}
else if (_inputDevice.ActiveId.StartsWith("controller") && _inputConfig is ControllerConfig)
{
SetValues(_inputConfig);
}
}
private void SetControllerSpecificFields()
{
_leftSideTriggerBox.Hide();
_rightSideTriggerBox.Hide();
switch (_controllerType.ActiveId)
{
case "JoyconLeft":
_leftSideTriggerBox.Show();
break;
case "JoyconRight":
_rightSideTriggerBox.Show();
break;
}
switch (_controllerType.ActiveId)
{
case "ProController":
_controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ProCon.svg", 400, 400);
break;
case "JoyconLeft":
_controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConLeft.svg", 400, 400);
break;
case "JoyconRight":
_controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConRight.svg", 400, 400);
break;
default:
_controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConPair.svg", 400, 400);
break;
}
}
private void ClearValues()
{
_lStickX.Label = "Unbound";
_lStickY.Label = "Unbound";
_lStickUp.Label = "Unbound";
_lStickDown.Label = "Unbound";
_lStickLeft.Label = "Unbound";
_lStickRight.Label = "Unbound";
_lStickButton.Label = "Unbound";
_dpadUp.Label = "Unbound";
_dpadDown.Label = "Unbound";
_dpadLeft.Label = "Unbound";
_dpadRight.Label = "Unbound";
_minus.Label = "Unbound";
_l.Label = "Unbound";
_zL.Label = "Unbound";
_lSl.Label = "Unbound";
_lSr.Label = "Unbound";
_rStickX.Label = "Unbound";
_rStickY.Label = "Unbound";
_rStickUp.Label = "Unbound";
_rStickDown.Label = "Unbound";
_rStickLeft.Label = "Unbound";
_rStickRight.Label = "Unbound";
_rStickButton.Label = "Unbound";
_a.Label = "Unbound";
_b.Label = "Unbound";
_x.Label = "Unbound";
_y.Label = "Unbound";
_plus.Label = "Unbound";
_r.Label = "Unbound";
_zR.Label = "Unbound";
_rSl.Label = "Unbound";
_rSr.Label = "Unbound";
_controllerDeadzoneLeft.Value = 0;
_controllerDeadzoneRight.Value = 0;
_controllerTriggerThreshold.Value = 0;
}
private void SetValues(InputConfig config)
{
switch (config)
{
case KeyboardConfig keyboardConfig:
_controllerType.SetActiveId(keyboardConfig.ControllerType.ToString());
_lStickUp.Label = keyboardConfig.LeftJoycon.StickUp.ToString();
_lStickDown.Label = keyboardConfig.LeftJoycon.StickDown.ToString();
_lStickLeft.Label = keyboardConfig.LeftJoycon.StickLeft.ToString();
_lStickRight.Label = keyboardConfig.LeftJoycon.StickRight.ToString();
_lStickButton.Label = keyboardConfig.LeftJoycon.StickButton.ToString();
_dpadUp.Label = keyboardConfig.LeftJoycon.DPadUp.ToString();
_dpadDown.Label = keyboardConfig.LeftJoycon.DPadDown.ToString();
_dpadLeft.Label = keyboardConfig.LeftJoycon.DPadLeft.ToString();
_dpadRight.Label = keyboardConfig.LeftJoycon.DPadRight.ToString();
_minus.Label = keyboardConfig.LeftJoycon.ButtonMinus.ToString();
_l.Label = keyboardConfig.LeftJoycon.ButtonL.ToString();
_zL.Label = keyboardConfig.LeftJoycon.ButtonZl.ToString();
_lSl.Label = keyboardConfig.LeftJoycon.ButtonSl.ToString();
_lSr.Label = keyboardConfig.LeftJoycon.ButtonSr.ToString();
_rStickUp.Label = keyboardConfig.RightJoycon.StickUp.ToString();
_rStickDown.Label = keyboardConfig.RightJoycon.StickDown.ToString();
_rStickLeft.Label = keyboardConfig.RightJoycon.StickLeft.ToString();
_rStickRight.Label = keyboardConfig.RightJoycon.StickRight.ToString();
_rStickButton.Label = keyboardConfig.RightJoycon.StickButton.ToString();
_a.Label = keyboardConfig.RightJoycon.ButtonA.ToString();
_b.Label = keyboardConfig.RightJoycon.ButtonB.ToString();
_x.Label = keyboardConfig.RightJoycon.ButtonX.ToString();
_y.Label = keyboardConfig.RightJoycon.ButtonY.ToString();
_plus.Label = keyboardConfig.RightJoycon.ButtonPlus.ToString();
_r.Label = keyboardConfig.RightJoycon.ButtonR.ToString();
_zR.Label = keyboardConfig.RightJoycon.ButtonZr.ToString();
_rSl.Label = keyboardConfig.RightJoycon.ButtonSl.ToString();
_rSr.Label = keyboardConfig.RightJoycon.ButtonSr.ToString();
break;
case ControllerConfig controllerConfig:
_controllerType.SetActiveId(controllerConfig.ControllerType.ToString());
_lStickX.Label = controllerConfig.LeftJoycon.StickX.ToString();
_invertLStickX.Active = controllerConfig.LeftJoycon.InvertStickX;
_lStickY.Label = controllerConfig.LeftJoycon.StickY.ToString();
_invertLStickY.Active = controllerConfig.LeftJoycon.InvertStickY;
_lStickButton.Label = controllerConfig.LeftJoycon.StickButton.ToString();
_dpadUp.Label = controllerConfig.LeftJoycon.DPadUp.ToString();
_dpadDown.Label = controllerConfig.LeftJoycon.DPadDown.ToString();
_dpadLeft.Label = controllerConfig.LeftJoycon.DPadLeft.ToString();
_dpadRight.Label = controllerConfig.LeftJoycon.DPadRight.ToString();
_minus.Label = controllerConfig.LeftJoycon.ButtonMinus.ToString();
_l.Label = controllerConfig.LeftJoycon.ButtonL.ToString();
_zL.Label = controllerConfig.LeftJoycon.ButtonZl.ToString();
_lSl.Label = controllerConfig.LeftJoycon.ButtonSl.ToString();
_lSr.Label = controllerConfig.LeftJoycon.ButtonSr.ToString();
_rStickX.Label = controllerConfig.RightJoycon.StickX.ToString();
_invertRStickX.Active = controllerConfig.RightJoycon.InvertStickX;
_rStickY.Label = controllerConfig.RightJoycon.StickY.ToString();
_invertRStickY.Active = controllerConfig.RightJoycon.InvertStickY;
_rStickButton.Label = controllerConfig.RightJoycon.StickButton.ToString();
_a.Label = controllerConfig.RightJoycon.ButtonA.ToString();
_b.Label = controllerConfig.RightJoycon.ButtonB.ToString();
_x.Label = controllerConfig.RightJoycon.ButtonX.ToString();
_y.Label = controllerConfig.RightJoycon.ButtonY.ToString();
_plus.Label = controllerConfig.RightJoycon.ButtonPlus.ToString();
_r.Label = controllerConfig.RightJoycon.ButtonR.ToString();
_zR.Label = controllerConfig.RightJoycon.ButtonZr.ToString();
_rSl.Label = controllerConfig.RightJoycon.ButtonSl.ToString();
_rSr.Label = controllerConfig.RightJoycon.ButtonSr.ToString();
_controllerDeadzoneLeft.Value = controllerConfig.DeadzoneLeft;
_controllerDeadzoneRight.Value = controllerConfig.DeadzoneRight;
_controllerTriggerThreshold.Value = controllerConfig.TriggerThreshold;
break;
}
}
private InputConfig GetValues()
{
if (_inputDevice.ActiveId.StartsWith("keyboard"))
{
Enum.TryParse(_lStickUp.Label, out Key lStickUp);
Enum.TryParse(_lStickDown.Label, out Key lStickDown);
Enum.TryParse(_lStickLeft.Label, out Key lStickLeft);
Enum.TryParse(_lStickRight.Label, out Key lStickRight);
Enum.TryParse(_lStickButton.Label, out Key lStickButton);
Enum.TryParse(_dpadUp.Label, out Key lDPadUp);
Enum.TryParse(_dpadDown.Label, out Key lDPadDown);
Enum.TryParse(_dpadLeft.Label, out Key lDPadLeft);
Enum.TryParse(_dpadRight.Label, out Key lDPadRight);
Enum.TryParse(_minus.Label, out Key lButtonMinus);
Enum.TryParse(_l.Label, out Key lButtonL);
Enum.TryParse(_zL.Label, out Key lButtonZl);
Enum.TryParse(_lSl.Label, out Key lButtonSl);
Enum.TryParse(_lSr.Label, out Key lButtonSr);
Enum.TryParse(_rStickUp.Label, out Key rStickUp);
Enum.TryParse(_rStickDown.Label, out Key rStickDown);
Enum.TryParse(_rStickLeft.Label, out Key rStickLeft);
Enum.TryParse(_rStickRight.Label, out Key rStickRight);
Enum.TryParse(_rStickButton.Label, out Key rStickButton);
Enum.TryParse(_a.Label, out Key rButtonA);
Enum.TryParse(_b.Label, out Key rButtonB);
Enum.TryParse(_x.Label, out Key rButtonX);
Enum.TryParse(_y.Label, out Key rButtonY);
Enum.TryParse(_plus.Label, out Key rButtonPlus);
Enum.TryParse(_r.Label, out Key rButtonR);
Enum.TryParse(_zR.Label, out Key rButtonZr);
Enum.TryParse(_rSl.Label, out Key rButtonSl);
Enum.TryParse(_rSr.Label, out Key rButtonSr);
return new KeyboardConfig
{
Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
PlayerIndex = _playerIndex,
LeftJoycon = new NpadKeyboardLeft
{
StickUp = lStickUp,
StickDown = lStickDown,
StickLeft = lStickLeft,
StickRight = lStickRight,
StickButton = lStickButton,
DPadUp = lDPadUp,
DPadDown = lDPadDown,
DPadLeft = lDPadLeft,
DPadRight = lDPadRight,
ButtonMinus = lButtonMinus,
ButtonL = lButtonL,
ButtonZl = lButtonZl,
ButtonSl = lButtonSl,
ButtonSr = lButtonSr
},
RightJoycon = new NpadKeyboardRight
{
StickUp = rStickUp,
StickDown = rStickDown,
StickLeft = rStickLeft,
StickRight = rStickRight,
StickButton = rStickButton,
ButtonA = rButtonA,
ButtonB = rButtonB,
ButtonX = rButtonX,
ButtonY = rButtonY,
ButtonPlus = rButtonPlus,
ButtonR = rButtonR,
ButtonZr = rButtonZr,
ButtonSl = rButtonSl,
ButtonSr = rButtonSr
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab //TODO: Make this an option in the GUI
}
};
}
if (_inputDevice.ActiveId.StartsWith("controller"))
{
Enum.TryParse(_lStickX.Label, out ControllerInputId lStickX);
Enum.TryParse(_lStickY.Label, out ControllerInputId lStickY);
Enum.TryParse(_lStickButton.Label, out ControllerInputId lStickButton);
Enum.TryParse(_minus.Label, out ControllerInputId lButtonMinus);
Enum.TryParse(_l.Label, out ControllerInputId lButtonL);
Enum.TryParse(_zL.Label, out ControllerInputId lButtonZl);
Enum.TryParse(_lSl.Label, out ControllerInputId lButtonSl);
Enum.TryParse(_lSr.Label, out ControllerInputId lButtonSr);
Enum.TryParse(_dpadUp.Label, out ControllerInputId lDPadUp);
Enum.TryParse(_dpadDown.Label, out ControllerInputId lDPadDown);
Enum.TryParse(_dpadLeft.Label, out ControllerInputId lDPadLeft);
Enum.TryParse(_dpadRight.Label, out ControllerInputId lDPadRight);
Enum.TryParse(_rStickX.Label, out ControllerInputId rStickX);
Enum.TryParse(_rStickY.Label, out ControllerInputId rStickY);
Enum.TryParse(_rStickButton.Label, out ControllerInputId rStickButton);
Enum.TryParse(_a.Label, out ControllerInputId rButtonA);
Enum.TryParse(_b.Label, out ControllerInputId rButtonB);
Enum.TryParse(_x.Label, out ControllerInputId rButtonX);
Enum.TryParse(_y.Label, out ControllerInputId rButtonY);
Enum.TryParse(_plus.Label, out ControllerInputId rButtonPlus);
Enum.TryParse(_r.Label, out ControllerInputId rButtonR);
Enum.TryParse(_zR.Label, out ControllerInputId rButtonZr);
Enum.TryParse(_rSl.Label, out ControllerInputId rButtonSl);
Enum.TryParse(_rSr.Label, out ControllerInputId rButtonSr);
return new ControllerConfig
{
Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
ControllerType = Enum.Parse<ControllerType>(_controllerType.ActiveId),
PlayerIndex = _playerIndex,
DeadzoneLeft = (float)_controllerDeadzoneLeft.Value,
DeadzoneRight = (float)_controllerDeadzoneRight.Value,
TriggerThreshold = (float)_controllerTriggerThreshold.Value,
LeftJoycon = new NpadControllerLeft
{
InvertStickX = _invertLStickX.Active,
StickX = lStickX,
InvertStickY = _invertLStickY.Active,
StickY = lStickY,
StickButton = lStickButton,
ButtonMinus = lButtonMinus,
ButtonL = lButtonL,
ButtonZl = lButtonZl,
ButtonSl = lButtonSl,
ButtonSr = lButtonSr,
DPadUp = lDPadUp,
DPadDown = lDPadDown,
DPadLeft = lDPadLeft,
DPadRight = lDPadRight
},
RightJoycon = new NpadControllerRight
{
InvertStickX = _invertRStickX.Active,
StickX = rStickX,
InvertStickY = _invertRStickY.Active,
StickY = rStickY,
StickButton = rStickButton,
ButtonA = rButtonA,
ButtonB = rButtonB,
ButtonX = rButtonX,
ButtonY = rButtonY,
ButtonPlus = rButtonPlus,
ButtonR = rButtonR,
ButtonZr = rButtonZr,
ButtonSl = rButtonSl,
ButtonSr = rButtonSr
}
};
}
if (!_inputDevice.ActiveId.StartsWith("disabled"))
{
GtkDialog.CreateErrorDialog("Some fields entered where invalid and therefore your config was not saved.");
}
return null;
}
private static bool IsAnyKeyPressed(out Key pressedKey, int index = 0)
{
KeyboardState keyboardState = Keyboard.GetState(index);
foreach (Key key in Enum.GetValues(typeof(Key)))
{
if (keyboardState.IsKeyDown((OpenTK.Input.Key)key))
{
pressedKey = key;
return true;
}
}
pressedKey = Key.Unbound;
return false;
}
private static bool IsAnyButtonPressed(out ControllerInputId pressedButton, int index, double triggerThreshold)
{
JoystickState joystickState = Joystick.GetState(index);
JoystickCapabilities joystickCapabilities = Joystick.GetCapabilities(index);
//Buttons
for (int i = 0; i != joystickCapabilities.ButtonCount; i++)
{
if (joystickState.IsButtonDown(i))
{
Enum.TryParse($"Button{i}", out pressedButton);
return true;
}
}
//Axis
for (int i = 0; i != joystickCapabilities.AxisCount; i++)
{
if (joystickState.GetAxis(i) > 0.5f && joystickState.GetAxis(i) > triggerThreshold)
{
Enum.TryParse($"Axis{i}", out pressedButton);
return true;
}
}
//Hats
for (int i = 0; i != joystickCapabilities.HatCount; i++)
{
JoystickHatState hatState = joystickState.GetHat((JoystickHat)i);
string pos = null;
if (hatState.IsUp) pos = "Up";
if (hatState.IsDown) pos = "Down";
if (hatState.IsLeft) pos = "Left";
if (hatState.IsRight) pos = "Right";
if (pos == null) continue;
Enum.TryParse($"Hat{i}{pos}", out pressedButton);
return true;
}
pressedButton = ControllerInputId.Unbound;
return false;
}
private string GetProfileBasePath()
{
string path = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "profiles");
if (_inputDevice.ActiveId.StartsWith("keyboard"))
{
path = System.IO.Path.Combine(path, "keyboard");
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
{
path = System.IO.Path.Combine(path, "controller");
}
return path;
}
//Events
private void InputDevice_Changed(object sender, EventArgs args)
{
SetAvailableOptions();
SetControllerSpecificFields();
if (_inputDevice.ActiveId != null) SetProfiles();
}
private void Controller_Changed(object sender, EventArgs args)
{
SetControllerSpecificFields();
}
private void RefreshInputDevicesButton_Pressed(object sender, EventArgs args)
{
UpdateInputDeviceList();
_refreshInputDevicesButton.SetStateFlags(0, true);
}
private void Button_Pressed(object sender, EventArgs args)
{
if (_isWaitingForInput)
{
return;
}
_isWaitingForInput = true;
Thread inputThread = new Thread(() =>
{
Button button = (ToggleButton)sender;
if (_inputDevice.ActiveId.StartsWith("keyboard"))
{
Key pressedKey;
int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
while (!IsAnyKeyPressed(out pressedKey, index))
{
if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsKeyDown(OpenTK.Input.Key.Escape))
{
Application.Invoke(delegate
{
button.SetStateFlags(0, true);
});
_isWaitingForInput = false;
return;
}
}
Application.Invoke(delegate
{
button.Label = pressedKey.ToString();
button.SetStateFlags(0, true);
});
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
{
ControllerInputId pressedButton;
int index = int.Parse(_inputDevice.ActiveId.Split("/")[1]);
while (!IsAnyButtonPressed(out pressedButton, index, _controllerTriggerThreshold.Value))
{
if (Mouse.GetState().IsAnyButtonDown || Keyboard.GetState().IsAnyKeyDown)
{
Application.Invoke(delegate
{
button.SetStateFlags(0, true);
});
_isWaitingForInput = false;
return;
}
}
Application.Invoke(delegate
{
button.Label = pressedButton.ToString();
button.SetStateFlags(0, true);
});
}
_isWaitingForInput = false;
});
inputThread.Name = "GUI.InputThread";
inputThread.IsBackground = true;
inputThread.Start();
}
private void SetProfiles()
{
string basePath = GetProfileBasePath();
if (!Directory.Exists(basePath))
{
Directory.CreateDirectory(basePath);
}
_profile.RemoveAll();
_profile.Append("default", "Default");
foreach (string profile in Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories))
{
_profile.Append(System.IO.Path.GetFileName(profile), System.IO.Path.GetFileNameWithoutExtension(profile));
}
}
private void ProfileLoad_Activated(object sender, EventArgs args)
{
((ToggleButton)sender).SetStateFlags(0, true);
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == null) return;
InputConfig config = null;
int pos = _profile.Active;
if (_profile.ActiveId == "default")
{
if (_inputDevice.ActiveId.StartsWith("keyboard"))
{
config = new KeyboardConfig
{
Index = 0,
ControllerType = ControllerType.JoyconPair,
LeftJoycon = new NpadKeyboardLeft
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
DPadUp = Key.Up,
DPadDown = Key.Down,
DPadLeft = Key.Left,
DPadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound
},
RightJoycon = new NpadKeyboardRight
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
}
};
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
{
config = new ControllerConfig
{
Index = 0,
ControllerType = ControllerType.ProController,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
TriggerThreshold = 0.5f,
LeftJoycon = new NpadControllerLeft
{
StickX = ControllerInputId.Axis0,
StickY = ControllerInputId.Axis1,
StickButton = ControllerInputId.Button8,
DPadUp = ControllerInputId.Hat0Up,
DPadDown = ControllerInputId.Hat0Down,
DPadLeft = ControllerInputId.Hat0Left,
DPadRight = ControllerInputId.Hat0Right,
ButtonMinus = ControllerInputId.Button6,
ButtonL = ControllerInputId.Button4,
ButtonZl = ControllerInputId.Axis2,
ButtonSl = ControllerInputId.Unbound,
ButtonSr = ControllerInputId.Unbound,
InvertStickX = false,
InvertStickY = false
},
RightJoycon = new NpadControllerRight
{
StickX = ControllerInputId.Axis3,
StickY = ControllerInputId.Axis4,
StickButton = ControllerInputId.Button9,
ButtonA = ControllerInputId.Button1,
ButtonB = ControllerInputId.Button0,
ButtonX = ControllerInputId.Button3,
ButtonY = ControllerInputId.Button2,
ButtonPlus = ControllerInputId.Button7,
ButtonR = ControllerInputId.Button5,
ButtonZr = ControllerInputId.Axis5,
ButtonSl = ControllerInputId.Unbound,
ButtonSr = ControllerInputId.Unbound,
InvertStickX = false,
InvertStickY = false
}
};
}
}
else
{
string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
if (!File.Exists(path))
{
if (pos >= 0)
{
_profile.Remove(pos);
}
return;
}
using (Stream stream = File.OpenRead(path))
{
try
{
config = JsonHelper.Deserialize<ControllerConfig>(stream);
}
catch (ArgumentException)
{
try
{
config = JsonHelper.Deserialize<KeyboardConfig>(stream);
}
catch { }
}
}
}
SetValues(config);
}
private void ProfileAdd_Activated(object sender, EventArgs args)
{
((ToggleButton)sender).SetStateFlags(0, true);
if (_inputDevice.ActiveId == "disabled") return;
InputConfig inputConfig = GetValues();
ProfileDialog profileDialog = new ProfileDialog();
if (inputConfig == null) return;
if (profileDialog.Run() == (int)ResponseType.Ok)
{
string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
string jsonString;
if (inputConfig is KeyboardConfig keyboardConfig)
{
jsonString = JsonHelper.Serialize(keyboardConfig, true);
}
else
{
jsonString = JsonHelper.Serialize(inputConfig as ControllerConfig, true);
}
File.WriteAllText(path, jsonString);
}
profileDialog.Dispose();
SetProfiles();
}
private void ProfileRemove_Activated(object sender, EventArgs args)
{
((ToggleButton) sender).SetStateFlags(0, true);
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == "default" || _profile.ActiveId == null) return;
MessageDialog confirmDialog = GtkDialog.CreateConfirmationDialog("Deleting Profile", "This action is irreversible, are your sure you want to continue?");
if (confirmDialog.Run() == (int)ResponseType.Yes)
{
string path = System.IO.Path.Combine(GetProfileBasePath(), _profile.ActiveId);
if (File.Exists(path))
{
File.Delete(path);
}
SetProfiles();
}
}
private void SaveToggle_Activated(object sender, EventArgs args)
{
InputConfig inputConfig = GetValues();
if (_inputConfig == null && inputConfig != null)
{
ConfigurationState.Instance.Hid.InputConfig.Value.Add(inputConfig);
}
else
{
if (_inputDevice.ActiveId == "disabled")
{
ConfigurationState.Instance.Hid.InputConfig.Value.Remove(_inputConfig);
}
else if (inputConfig != null)
{
int index = ConfigurationState.Instance.Hid.InputConfig.Value.IndexOf(_inputConfig);
ConfigurationState.Instance.Hid.InputConfig.Value[index] = inputConfig;
}
}
Dispose();
}
private void CloseToggle_Activated(object sender, EventArgs args)
{
Dispose();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,24 @@
using Gdk;
using Gdk;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using OpenTK.Platform;
using Ryujinx.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.Ui;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Ryujinx.Ui
{
public class GLRenderer : GLWidget
public class GlRenderer : GLWidget
{
private const int SwitchPanelWidth = 1280;
private const int SwitchPanelWidth = 1280;
private const int SwitchPanelHeight = 720;
private const int TargetFps = 60;
private const int TargetFps = 60;
public ManualResetEvent WaitEvent { get; set; }
@ -32,7 +30,7 @@ namespace Ryujinx.Ui
private double _mouseX;
private double _mouseY;
private bool _mousePressed;
private bool _mousePressed;
private bool _toggleFullscreen;
@ -46,11 +44,9 @@ namespace Ryujinx.Ui
private Renderer _renderer;
private HotkeyButtons _prevHotkeyButtons = 0;
private HotkeyButtons _prevHotkeyButtons;
private Input.NpadController _primaryController;
public GLRenderer(Switch device)
public GlRenderer(Switch device)
: base (GetGraphicsMode(),
3, 3,
GraphicsContextFlags.ForwardCompatible)
@ -59,8 +55,8 @@ namespace Ryujinx.Ui
_device = device;
this.Initialized += GLRenderer_Initialized;
this.Destroyed += GLRenderer_Destroyed;
this.Initialized += GLRenderer_Initialized;
this.Destroyed += GLRenderer_Destroyed;
this.ShuttingDown += GLRenderer_ShuttingDown;
Initialize();
@ -69,25 +65,18 @@ namespace Ryujinx.Ui
_ticksPerFrame = System.Diagnostics.Stopwatch.Frequency / TargetFps;
_primaryController = new Input.NpadController(ConfigurationState.Instance.Hid.JoystickControls);
AddEvents((int)(Gdk.EventMask.ButtonPressMask
| Gdk.EventMask.ButtonReleaseMask
| Gdk.EventMask.PointerMotionMask
| Gdk.EventMask.KeyPressMask
| Gdk.EventMask.KeyReleaseMask));
AddEvents((int)(EventMask.ButtonPressMask
| EventMask.ButtonReleaseMask
| EventMask.PointerMotionMask
| EventMask.KeyPressMask
| EventMask.KeyReleaseMask));
this.Shown += Renderer_Shown;
}
private static GraphicsMode GetGraphicsMode()
{
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
return new GraphicsMode(new ColorFormat(24));
}
return new GraphicsMode(new ColorFormat());
return Environment.OSVersion.Platform == PlatformID.Unix ? new GraphicsMode(new ColorFormat(24)) : new GraphicsMode(new ColorFormat());
}
private void GLRenderer_ShuttingDown(object sender, EventArgs args)
@ -117,11 +106,11 @@ namespace Ryujinx.Ui
public void HandleScreenState(KeyboardState keyboard)
{
bool toggleFullscreen = keyboard.IsKeyDown(OpenTK.Input.Key.F11)
bool toggleFullscreen = keyboard.IsKeyDown(OpenTK.Input.Key.F11)
|| ((keyboard.IsKeyDown(OpenTK.Input.Key.AltLeft)
|| keyboard.IsKeyDown(OpenTK.Input.Key.AltRight))
&& keyboard.IsKeyDown(OpenTK.Input.Key.Enter))
|| keyboard.IsKeyDown(OpenTK.Input.Key.Escape);
|| keyboard.IsKeyDown(OpenTK.Input.Key.Escape);
bool fullScreenToggled = ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen);
@ -165,7 +154,7 @@ namespace Ryujinx.Ui
protected override bool OnConfigureEvent(EventConfigure evnt)
{
var result = base.OnConfigureEvent(evnt);
bool result = base.OnConfigureEvent(evnt);
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
@ -184,7 +173,7 @@ namespace Ryujinx.Ui
Gtk.Window parent = this.Toplevel as Gtk.Window;
parent.FocusInEvent += Parent_FocusInEvent;
parent.FocusInEvent += Parent_FocusInEvent;
parent.FocusOutEvent += Parent_FocusOutEvent;
Gtk.Application.Invoke(delegate
@ -347,7 +336,7 @@ namespace Ryujinx.Ui
_device.EnableDeviceVsync,
$"Host: {_device.Statistics.GetSystemFrameRate():00.00} FPS",
$"Game: {_device.Statistics.GetGameFrameRate():00.00} FPS",
$"GPU: {_renderer.GpuVendor}"));
$"GPU: {_renderer.GpuVendor}"));
_ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
}
@ -382,83 +371,127 @@ namespace Ryujinx.Ui
return false;
}
HotkeyButtons currentHotkeyButtons = 0;
ControllerKeys currentButton = 0;
JoystickPosition leftJoystick;
JoystickPosition rightJoystick;
KeyboardInput? hidKeyboard = null;
int leftJoystickDx = 0;
int leftJoystickDy = 0;
int rightJoystickDx = 0;
int rightJoystickDy = 0;
// OpenTK always captures keyboard events, even if out of focus, so check if window is focused.
if (IsFocused)
{
KeyboardState keyboard = OpenTK.Input.Keyboard.GetState();
Gtk.Application.Invoke(delegate
{
HandleScreenState(keyboard);
HandleScreenState(OpenTK.Input.Keyboard.GetState());
});
}
// Normal Input
currentHotkeyButtons = KeyboardControls.GetHotkeyButtons(ConfigurationState.Instance.Hid.KeyboardControls, keyboard);
currentButton = KeyboardControls.GetButtons(ConfigurationState.Instance.Hid.KeyboardControls, keyboard);
List<GamepadInput> gamepadInputs = new List<GamepadInput>();
if (ConfigurationState.Instance.Hid.EnableKeyboard)
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
{
ControllerKeys currentButton = 0;
JoystickPosition leftJoystick = new JoystickPosition();
JoystickPosition rightJoystick = new JoystickPosition();
KeyboardInput? hidKeyboard = null;
int leftJoystickDx = 0;
int leftJoystickDy = 0;
int rightJoystickDx = 0;
int rightJoystickDy = 0;
if (inputConfig is KeyboardConfig keyboardConfig)
{
hidKeyboard = KeyboardControls.GetKeysDown(ConfigurationState.Instance.Hid.KeyboardControls, keyboard);
if (IsFocused)
{
// Keyboard Input
KeyboardController keyboardController = new KeyboardController(keyboardConfig);
currentButton = keyboardController.GetButtons();
(leftJoystickDx, leftJoystickDy) = keyboardController.GetLeftStick();
(rightJoystickDx, rightJoystickDy) = keyboardController.GetRightStick();
leftJoystick = new JoystickPosition
{
Dx = leftJoystickDx,
Dy = leftJoystickDy
};
rightJoystick = new JoystickPosition
{
Dx = rightJoystickDx,
Dy = rightJoystickDy
};
if (ConfigurationState.Instance.Hid.EnableKeyboard)
{
hidKeyboard = keyboardController.GetKeysDown();
}
if (!hidKeyboard.HasValue)
{
hidKeyboard = new KeyboardInput
{
Modifier = 0,
Keys = new int[0x8]
};
}
if (ConfigurationState.Instance.Hid.EnableKeyboard)
{
_device.Hid.Keyboard.Update(hidKeyboard.Value);
}
// Toggle vsync
HotkeyButtons currentHotkeyButtons = keyboardController.GetHotkeyButtons();
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
{
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
}
_prevHotkeyButtons = currentHotkeyButtons;
}
}
else if (inputConfig is Common.Configuration.Hid.ControllerConfig controllerConfig)
{
// Controller Input
JoystickController joystickController = new JoystickController(controllerConfig);
currentButton |= joystickController.GetButtons();
(leftJoystickDx, leftJoystickDy) = joystickController.GetLeftStick();
(rightJoystickDx, rightJoystickDy) = joystickController.GetRightStick();
leftJoystick = new JoystickPosition
{
Dx = controllerConfig.LeftJoycon.InvertStickX ? -leftJoystickDx : leftJoystickDx,
Dy = controllerConfig.LeftJoycon.InvertStickY ? -leftJoystickDy : leftJoystickDy
};
rightJoystick = new JoystickPosition
{
Dx = controllerConfig.RightJoycon.InvertStickX ? -rightJoystickDx : rightJoystickDx,
Dy = controllerConfig.RightJoycon.InvertStickY ? -rightJoystickDy : rightJoystickDy
};
}
(leftJoystickDx, leftJoystickDy) = KeyboardControls.GetLeftStick(ConfigurationState.Instance.Hid.KeyboardControls, keyboard);
(rightJoystickDx, rightJoystickDy) = KeyboardControls.GetRightStick(ConfigurationState.Instance.Hid.KeyboardControls, keyboard);
}
currentButton |= _device.Hid.UpdateStickButtons(leftJoystick, rightJoystick);
if (!hidKeyboard.HasValue)
{
hidKeyboard = new KeyboardInput
gamepadInputs.Add(new GamepadInput
{
Modifier = 0,
Keys = new int[0x8]
};
PlayerId = (HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex,
Buttons = currentButton,
LStick = leftJoystick,
RStick = rightJoystick
});
}
currentButton |= _primaryController.GetButtons();
// Keyboard has priority stick-wise
if (leftJoystickDx == 0 && leftJoystickDy == 0)
{
(leftJoystickDx, leftJoystickDy) = _primaryController.GetLeftStick();
}
if (rightJoystickDx == 0 && rightJoystickDy == 0)
{
(rightJoystickDx, rightJoystickDy) = _primaryController.GetRightStick();
}
leftJoystick = new JoystickPosition
{
Dx = leftJoystickDx,
Dy = leftJoystickDy
};
rightJoystick = new JoystickPosition
{
Dx = rightJoystickDx,
Dy = rightJoystickDy
};
currentButton |= _device.Hid.UpdateStickButtons(leftJoystick, rightJoystick);
_device.Hid.Npads.SetGamepadsInput(gamepadInputs.ToArray());
//Touchscreen
bool hasTouch = false;
// Get screen touch position from left mouse click
// OpenTK always captures mouse events, even if out of focus, so check if window is focused.
if (IsFocused && _mousePressed)
{
int screenWidth = AllocatedWidth;
int screenWidth = AllocatedWidth;
int screenHeight = AllocatedHeight;
if (AllocatedWidth > (AllocatedHeight * SwitchPanelWidth) / SwitchPanelHeight)
@ -470,7 +503,7 @@ namespace Ryujinx.Ui
screenHeight = (AllocatedWidth * SwitchPanelHeight) / SwitchPanelWidth;
}
int startX = (AllocatedWidth - screenWidth) >> 1;
int startX = (AllocatedWidth - screenWidth) >> 1;
int startY = (AllocatedHeight - screenHeight) >> 1;
int endX = startX + screenWidth;
@ -496,7 +529,7 @@ namespace Ryujinx.Ui
// Placeholder values till more data is acquired
DiameterX = 10,
DiameterY = 10,
Angle = 90
Angle = 90
};
hasTouch = true;
@ -510,30 +543,8 @@ namespace Ryujinx.Ui
_device.Hid.Touchscreen.Update();
}
if (ConfigurationState.Instance.Hid.EnableKeyboard && hidKeyboard.HasValue)
{
_device.Hid.Keyboard.Update(hidKeyboard.Value);
}
_device.Hid.DebugPad.Update();
_device.Hid.Npads.SetGamepadsInput(new GamepadInput
{
PlayerId = PlayerIndex.Auto,
Buttons = currentButton,
LStick = leftJoystick,
RStick = rightJoystick
});
// Toggle vsync
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
{
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
}
_prevHotkeyButtons = currentHotkeyButtons;
return true;
}
}

View File

@ -3,33 +3,46 @@ using System.Reflection;
namespace Ryujinx.Ui
{
internal class GtkDialog
internal class GtkDialog : MessageDialog
{
internal static bool _isExitDialogOpen = false;
internal static void CreateDialog(string title, string text, string secondaryText)
private GtkDialog(string title, string mainText, string secondaryText,
MessageType messageType = MessageType.Other, ButtonsType buttonsType = ButtonsType.Ok) : base(null, DialogFlags.Modal, messageType, buttonsType, null)
{
MessageDialog errorDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, null)
{
Title = title,
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
Text = text,
SecondaryText = secondaryText,
WindowPosition = WindowPosition.Center
};
errorDialog.SetSizeRequest(100, 20);
errorDialog.Run();
errorDialog.Dispose();
Title = title;
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
Text = mainText;
SecondaryText = secondaryText;
WindowPosition = WindowPosition.Center;
Response += GtkDialog_Response;
SetSizeRequest(100, 20);
}
internal static void CreateWarningDialog(string text, string secondaryText)
private void GtkDialog_Response(object sender, ResponseArgs args)
{
CreateDialog("Ryujinx - Warning", text, secondaryText);
Dispose();
}
internal static void CreateInfoDialog(string title, string mainText, string secondaryText)
{
new GtkDialog(title, mainText, secondaryText, MessageType.Info).Run();
}
internal static void CreateWarningDialog(string mainText, string secondaryText)
{
new GtkDialog("Ryujinx - Warning", mainText, secondaryText, MessageType.Warning).Run();
}
internal static void CreateErrorDialog(string errorMessage)
{
CreateDialog("Ryujinx - Error", "Ryujinx has encountered an error", errorMessage);
new GtkDialog("Ryujinx - Error", "Ryujinx has encountered an error", errorMessage, MessageType.Error).Run();
}
internal static MessageDialog CreateConfirmationDialog(string mainText, string secondaryText = "")
{
return new GtkDialog("Ryujinx - Confirmation", mainText, secondaryText, MessageType.Question, ButtonsType.YesNo);
}
internal static bool CreateExitDialog()
@ -40,27 +53,11 @@ namespace Ryujinx.Ui
}
_isExitDialogOpen = true;
MessageDialog messageDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Question, ButtonsType.OkCancel, null)
{
Title = "Ryujinx - Exit",
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
Text = "Are you sure you want to stop emulation?",
SecondaryText = "All unsaved data will be lost",
WindowPosition = WindowPosition.Center
};
messageDialog.SetSizeRequest(100, 20);
ResponseType res = (ResponseType)messageDialog.Run();
messageDialog.Dispose();
ResponseType res = (ResponseType)new GtkDialog("Ryujinx - Exit", "Are you sure you want to stop emulation?",
"All unsaved data will be lost", MessageType.Question, ButtonsType.YesNo).Run();
_isExitDialogOpen = false;
if (res == ResponseType.Ok)
{
return true;
}
return false;
return res == ResponseType.Yes;
}
}
}

View File

@ -0,0 +1,149 @@
using OpenTK;
using OpenTK.Input;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE.HOS.Services.Hid;
using System;
using ControllerConfig = Ryujinx.Common.Configuration.Hid.ControllerConfig;
namespace Ryujinx.Ui
{
public class JoystickController
{
private readonly ControllerConfig _config;
// NOTE: This should be initialized AFTER GTK for compat reasons with OpenTK SDL2 backend and GTK on Linux.
// BODY: Usage of Joystick.GetState must be defer to after GTK full initialization. Otherwise, GTK will segfault because SDL2 was already init *sighs*
public JoystickController(ControllerConfig config)
{
_config = config;
}
private bool IsEnabled()
{
return Joystick.GetState(_config.Index).IsConnected;
}
public ControllerKeys GetButtons()
{
if (!IsEnabled())
{
return 0;
}
JoystickState joystickState = Joystick.GetState(_config.Index);
ControllerKeys buttons = 0;
if (IsActivated(joystickState, _config.LeftJoycon.DPadUp)) buttons |= ControllerKeys.DpadUp;
if (IsActivated(joystickState, _config.LeftJoycon.DPadDown)) buttons |= ControllerKeys.DpadDown;
if (IsActivated(joystickState, _config.LeftJoycon.DPadLeft)) buttons |= ControllerKeys.DpadLeft;
if (IsActivated(joystickState, _config.LeftJoycon.DPadRight)) buttons |= ControllerKeys.DpadRight;
if (IsActivated(joystickState, _config.LeftJoycon.StickButton)) buttons |= ControllerKeys.LStick;
if (IsActivated(joystickState, _config.LeftJoycon.ButtonMinus)) buttons |= ControllerKeys.Minus;
if (IsActivated(joystickState, _config.LeftJoycon.ButtonL)) buttons |= ControllerKeys.L;
if (IsActivated(joystickState, _config.LeftJoycon.ButtonZl)) buttons |= ControllerKeys.Zl;
if (IsActivated(joystickState, _config.LeftJoycon.ButtonSl)) buttons |= ControllerKeys.SlLeft;
if (IsActivated(joystickState, _config.LeftJoycon.ButtonSr)) buttons |= ControllerKeys.SrLeft;
if (IsActivated(joystickState, _config.RightJoycon.ButtonA)) buttons |= ControllerKeys.A;
if (IsActivated(joystickState, _config.RightJoycon.ButtonB)) buttons |= ControllerKeys.B;
if (IsActivated(joystickState, _config.RightJoycon.ButtonX)) buttons |= ControllerKeys.X;
if (IsActivated(joystickState, _config.RightJoycon.ButtonY)) buttons |= ControllerKeys.Y;
if (IsActivated(joystickState, _config.RightJoycon.StickButton)) buttons |= ControllerKeys.RStick;
if (IsActivated(joystickState, _config.RightJoycon.ButtonPlus)) buttons |= ControllerKeys.Plus;
if (IsActivated(joystickState, _config.RightJoycon.ButtonR)) buttons |= ControllerKeys.R;
if (IsActivated(joystickState, _config.RightJoycon.ButtonZr)) buttons |= ControllerKeys.Zr;
if (IsActivated(joystickState, _config.RightJoycon.ButtonSl)) buttons |= ControllerKeys.SlRight;
if (IsActivated(joystickState, _config.RightJoycon.ButtonSr)) buttons |= ControllerKeys.SrRight;
return buttons;
}
private bool IsActivated(JoystickState joystickState, ControllerInputId controllerInputId)
{
if (controllerInputId <= ControllerInputId.Button20)
{
return joystickState.IsButtonDown((int)controllerInputId);
}
else if (controllerInputId <= ControllerInputId.Axis5)
{
int axis = controllerInputId - ControllerInputId.Axis0;
return joystickState.GetAxis(axis) > _config.TriggerThreshold;
}
else if (controllerInputId <= ControllerInputId.Hat2Right)
{
int hat = (controllerInputId - ControllerInputId.Hat0Up) / 4;
int baseHatId = (int)ControllerInputId.Hat0Up + (hat * 4);
JoystickHatState hatState = joystickState.GetHat((JoystickHat)hat);
if (hatState.IsUp && ((int)controllerInputId % baseHatId == 0)) return true;
if (hatState.IsDown && ((int)controllerInputId % baseHatId == 1)) return true;
if (hatState.IsLeft && ((int)controllerInputId % baseHatId == 2)) return true;
if (hatState.IsRight && ((int)controllerInputId % baseHatId == 3)) return true;
}
return false;
}
public (short, short) GetLeftStick()
{
if (!IsEnabled())
{
return (0, 0);
}
return GetStick(_config.LeftJoycon.StickX, _config.LeftJoycon.StickY, _config.DeadzoneLeft);
}
public (short, short) GetRightStick()
{
if (!IsEnabled())
{
return (0, 0);
}
return GetStick(_config.RightJoycon.StickX, _config.RightJoycon.StickY, _config.DeadzoneRight);
}
private (short, short) GetStick(ControllerInputId stickXInputId, ControllerInputId stickYInputId, float deadzone)
{
if (stickXInputId < ControllerInputId.Axis0 || stickXInputId > ControllerInputId.Axis5 ||
stickYInputId < ControllerInputId.Axis0 || stickYInputId > ControllerInputId.Axis5)
{
return (0, 0);
}
JoystickState jsState = Joystick.GetState(_config.Index);
int xAxis = stickXInputId - ControllerInputId.Axis0;
int yAxis = stickYInputId - ControllerInputId.Axis0;
float xValue = jsState.GetAxis(xAxis);
float yValue = -jsState.GetAxis(yAxis); // Invert Y-axis
return ApplyDeadzone(new Vector2(xValue, yValue), deadzone);
}
private (short, short) ApplyDeadzone(Vector2 axis, float deadzone)
{
return (ClampAxis(MathF.Abs(axis.X) > deadzone ? axis.X : 0f),
ClampAxis(MathF.Abs(axis.Y) > deadzone ? axis.Y : 0f));
}
private static short ClampAxis(float value)
{
if (value <= -short.MaxValue)
{
return -short.MaxValue;
}
else
{
return (short)(value * short.MaxValue);
}
}
}
}

View File

@ -1,7 +1,7 @@
using System;
using OpenTK.Input;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.UI.Input;
namespace Ryujinx.Ui
{
@ -11,64 +11,85 @@ namespace Ryujinx.Ui
ToggleVSync = 1 << 0,
}
public static class KeyboardControls
public class KeyboardController
{
public static ControllerKeys GetButtons(NpadKeyboard npad, KeyboardState keyboard)
private readonly KeyboardConfig _config;
// NOTE: This should be initialized AFTER GTK for compat reasons with OpenTK SDL2 backend and GTK on Linux.
// BODY: Usage of Joystick.GetState must be defer to after GTK full initialization. Otherwise, GTK will segfault because SDL2 was already init *sighs*
public KeyboardController(KeyboardConfig config)
{
_config = config;
}
public ControllerKeys GetButtons()
{
KeyboardState keyboard = Keyboard.GetState(_config.Index);
ControllerKeys buttons = 0;
if (keyboard[(Key)npad.LeftJoycon.StickButton]) buttons |= ControllerKeys.LStick;
if (keyboard[(Key)npad.LeftJoycon.DPadUp]) buttons |= ControllerKeys.DpadUp;
if (keyboard[(Key)npad.LeftJoycon.DPadDown]) buttons |= ControllerKeys.DpadDown;
if (keyboard[(Key)npad.LeftJoycon.DPadLeft]) buttons |= ControllerKeys.DpadLeft;
if (keyboard[(Key)npad.LeftJoycon.DPadRight]) buttons |= ControllerKeys.DpadRight;
if (keyboard[(Key)npad.LeftJoycon.ButtonMinus]) buttons |= ControllerKeys.Minus;
if (keyboard[(Key)npad.LeftJoycon.ButtonL]) buttons |= ControllerKeys.L | ControllerKeys.Sl;
if (keyboard[(Key)npad.LeftJoycon.ButtonZl]) buttons |= ControllerKeys.Zl;
if (keyboard[(Key)_config.LeftJoycon.StickButton]) buttons |= ControllerKeys.LStick;
if (keyboard[(Key)_config.LeftJoycon.DPadUp]) buttons |= ControllerKeys.DpadUp;
if (keyboard[(Key)_config.LeftJoycon.DPadDown]) buttons |= ControllerKeys.DpadDown;
if (keyboard[(Key)_config.LeftJoycon.DPadLeft]) buttons |= ControllerKeys.DpadLeft;
if (keyboard[(Key)_config.LeftJoycon.DPadRight]) buttons |= ControllerKeys.DpadRight;
if (keyboard[(Key)_config.LeftJoycon.ButtonMinus]) buttons |= ControllerKeys.Minus;
if (keyboard[(Key)_config.LeftJoycon.ButtonL]) buttons |= ControllerKeys.L;
if (keyboard[(Key)_config.LeftJoycon.ButtonZl]) buttons |= ControllerKeys.Zl;
if (keyboard[(Key)_config.LeftJoycon.ButtonSl]) buttons |= ControllerKeys.SlLeft;
if (keyboard[(Key)_config.LeftJoycon.ButtonSr]) buttons |= ControllerKeys.SlRight;
if (keyboard[(Key)npad.RightJoycon.StickButton]) buttons |= ControllerKeys.RStick;
if (keyboard[(Key)npad.RightJoycon.ButtonA]) buttons |= ControllerKeys.A;
if (keyboard[(Key)npad.RightJoycon.ButtonB]) buttons |= ControllerKeys.B;
if (keyboard[(Key)npad.RightJoycon.ButtonX]) buttons |= ControllerKeys.X;
if (keyboard[(Key)npad.RightJoycon.ButtonY]) buttons |= ControllerKeys.Y;
if (keyboard[(Key)npad.RightJoycon.ButtonPlus]) buttons |= ControllerKeys.Plus;
if (keyboard[(Key)npad.RightJoycon.ButtonR]) buttons |= ControllerKeys.R | ControllerKeys.Sr;
if (keyboard[(Key)npad.RightJoycon.ButtonZr]) buttons |= ControllerKeys.Zr;
if (keyboard[(Key)_config.RightJoycon.StickButton]) buttons |= ControllerKeys.RStick;
if (keyboard[(Key)_config.RightJoycon.ButtonA]) buttons |= ControllerKeys.A;
if (keyboard[(Key)_config.RightJoycon.ButtonB]) buttons |= ControllerKeys.B;
if (keyboard[(Key)_config.RightJoycon.ButtonX]) buttons |= ControllerKeys.X;
if (keyboard[(Key)_config.RightJoycon.ButtonY]) buttons |= ControllerKeys.Y;
if (keyboard[(Key)_config.RightJoycon.ButtonPlus]) buttons |= ControllerKeys.Plus;
if (keyboard[(Key)_config.RightJoycon.ButtonR]) buttons |= ControllerKeys.R;
if (keyboard[(Key)_config.RightJoycon.ButtonZr]) buttons |= ControllerKeys.Zr;
if (keyboard[(Key)_config.RightJoycon.ButtonSl]) buttons |= ControllerKeys.SrLeft;
if (keyboard[(Key)_config.RightJoycon.ButtonSr]) buttons |= ControllerKeys.SrRight;
return buttons;
}
public static (short, short) GetLeftStick(NpadKeyboard npad, KeyboardState keyboard)
public (short, short) GetLeftStick()
{
KeyboardState keyboard = Keyboard.GetState(_config.Index);
short dx = 0;
short dy = 0;
if (keyboard[(Key)npad.LeftJoycon.StickUp]) dy = short.MaxValue;
if (keyboard[(Key)npad.LeftJoycon.StickDown]) dy = -short.MaxValue;
if (keyboard[(Key)npad.LeftJoycon.StickLeft]) dx = -short.MaxValue;
if (keyboard[(Key)npad.LeftJoycon.StickRight]) dx = short.MaxValue;
if (keyboard[(Key)_config.LeftJoycon.StickUp]) dy = short.MaxValue;
if (keyboard[(Key)_config.LeftJoycon.StickDown]) dy = -short.MaxValue;
if (keyboard[(Key)_config.LeftJoycon.StickLeft]) dx = -short.MaxValue;
if (keyboard[(Key)_config.LeftJoycon.StickRight]) dx = short.MaxValue;
return (dx, dy);
}
public static (short, short) GetRightStick(NpadKeyboard npad, KeyboardState keyboard)
public (short, short) GetRightStick()
{
KeyboardState keyboard = Keyboard.GetState(_config.Index);
short dx = 0;
short dy = 0;
if (keyboard[(Key)npad.RightJoycon.StickUp]) dy = short.MaxValue;
if (keyboard[(Key)npad.RightJoycon.StickDown]) dy = -short.MaxValue;
if (keyboard[(Key)npad.RightJoycon.StickLeft]) dx = -short.MaxValue;
if (keyboard[(Key)npad.RightJoycon.StickRight]) dx = short.MaxValue;
if (keyboard[(Key)_config.RightJoycon.StickUp]) dy = short.MaxValue;
if (keyboard[(Key)_config.RightJoycon.StickDown]) dy = -short.MaxValue;
if (keyboard[(Key)_config.RightJoycon.StickLeft]) dx = -short.MaxValue;
if (keyboard[(Key)_config.RightJoycon.StickRight]) dx = short.MaxValue;
return (dx, dy);
}
public static HotkeyButtons GetHotkeyButtons(NpadKeyboard npad, KeyboardState keyboard)
public HotkeyButtons GetHotkeyButtons()
{
KeyboardState keyboard = Keyboard.GetState(_config.Index);
HotkeyButtons buttons = 0;
if (keyboard[(Key)npad.Hotkeys.ToggleVsync]) buttons |= HotkeyButtons.ToggleVSync;
if (keyboard[(Key)_config.Hotkeys.ToggleVsync]) buttons |= HotkeyButtons.ToggleVSync;
return buttons;
}
@ -223,12 +244,14 @@ namespace Ryujinx.Ui
new KeyMappingEntry { TargetKey = Key.NumLock, Target = 10 },
};
public static KeyboardInput GetKeysDown(NpadKeyboard npad, KeyboardState keyboard)
public KeyboardInput GetKeysDown()
{
KeyboardState keyboard = Keyboard.GetState(_config.Index);
KeyboardInput hidKeyboard = new KeyboardInput
{
Modifier = 0,
Keys = new int[0x8]
Modifier = 0,
Keys = new int[0x8]
};
foreach (KeyMappingEntry entry in KeyMapping)

View File

@ -13,6 +13,7 @@ using Ryujinx.HLE.HOS.Services.Hid;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
@ -28,7 +29,7 @@ namespace Ryujinx.Ui
private static HLE.Switch _emulationContext;
private static GLRenderer _gLWidget;
private static GlRenderer _glWidget;
private static AutoResetEvent _deviceExitStatus = new AutoResetEvent(false);
@ -37,40 +38,38 @@ namespace Ryujinx.Ui
private static bool _updatingGameTable;
private static bool _gameLoaded;
private static bool _ending;
#pragma warning disable CS0169
private static bool _debuggerOpened;
#pragma warning restore CS0169
#pragma warning disable CS0169
private static Ryujinx.Debugger.Debugger _debugger;
private static bool _debuggerOpened;
private static Debugger.Debugger _debugger;
#pragma warning restore CS0169
#pragma warning disable CS0169, CS0649, IDE0044
[GUI] Window _mainWin;
[GUI] MenuBar _menuBar;
[GUI] Box _footerBox;
[GUI] MenuItem _fullScreen;
[GUI] Box _statusBar;
[GUI] MenuItem _stopEmulation;
[GUI] MenuItem _fullScreen;
[GUI] CheckMenuItem _favToggle;
[GUI] MenuItem _firmwareInstallFile;
[GUI] MenuItem _firmwareInstallDirectory;
[GUI] MenuItem _firmwareInstallFile;
[GUI] Label _hostStatus;
[GUI] MenuItem _openDebugger;
[GUI] CheckMenuItem _iconToggle;
[GUI] CheckMenuItem _appToggle;
[GUI] CheckMenuItem _developerToggle;
[GUI] CheckMenuItem _versionToggle;
[GUI] CheckMenuItem _appToggle;
[GUI] CheckMenuItem _timePlayedToggle;
[GUI] CheckMenuItem _versionToggle;
[GUI] CheckMenuItem _lastPlayedToggle;
[GUI] CheckMenuItem _fileExtToggle;
[GUI] CheckMenuItem _fileSizeToggle;
[GUI] CheckMenuItem _pathToggle;
[GUI] CheckMenuItem _fileSizeToggle;
[GUI] Label _gameStatus;
[GUI] TreeView _gameTable;
[GUI] ScrolledWindow _gameTableWindow;
[GUI] TreeSelection _gameTableSelection;
[GUI] ScrolledWindow _gameTableWindow;
[GUI] Label _gpuName;
[GUI] Label _progressLabel;
[GUI] Label _firmwareVersionLabel;
@ -96,9 +95,12 @@ namespace Ryujinx.Ui
this.DeleteEvent += Window_Close;
_fullScreen.Activated += FullScreen_Toggled;
this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
this.Title = $"Ryujinx {Program.Version}";
ApplicationLibrary.ApplicationAdded += Application_Added;
ApplicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
GLRenderer.StatusUpdatedEvent += Update_StatusBar;
GlRenderer.StatusUpdatedEvent += Update_StatusBar;
_gameTable.ButtonReleaseEvent += Row_Clicked;
@ -127,8 +129,6 @@ namespace Ryujinx.Ui
ApplyTheme();
_mainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
_mainWin.Title = $"Ryujinx {Program.Version}";
_stopEmulation.Sensitive = false;
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) _favToggle.Active = true;
@ -302,7 +302,7 @@ namespace Ryujinx.Ui
{
if (_gameLoaded)
{
GtkDialog.CreateDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again.");
GtkDialog.CreateInfoDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again.");
}
else
{
@ -415,7 +415,7 @@ namespace Ryujinx.Ui
#if MACOS_BUILD
CreateGameWindow(device);
#else
var windowThread = new Thread(() =>
Thread windowThread = new Thread(() =>
{
CreateGameWindow(device);
})
@ -443,35 +443,29 @@ namespace Ryujinx.Ui
private void CreateGameWindow(HLE.Switch device)
{
ControllerType type = (Ryujinx.Configuration.Hid.ControllerType)ConfigurationState.Instance.Hid.ControllerType switch {
Ryujinx.Configuration.Hid.ControllerType.ProController => ControllerType.ProController,
Ryujinx.Configuration.Hid.ControllerType.Handheld => ControllerType.Handheld,
Ryujinx.Configuration.Hid.ControllerType.NpadPair => ControllerType.JoyconPair,
Ryujinx.Configuration.Hid.ControllerType.NpadLeft => ControllerType.JoyconLeft,
Ryujinx.Configuration.Hid.ControllerType.NpadRight => ControllerType.JoyconRight,
_ => ControllerType.Handheld
};
device.Hid.Npads.AddControllers(ConfigurationState.Instance.Hid.InputConfig.Value.Select(inputConfig =>
new HLE.HOS.Services.Hid.ControllerConfig
{
Player = (PlayerIndex)inputConfig.PlayerIndex,
Type = (ControllerType)inputConfig.ControllerType
}
).ToArray());
device.Hid.Npads.AddControllers(new ControllerConfig {
Player = PlayerIndex.Player1,
Type = type
});
_gLWidget = new GLRenderer(_emulationContext);
_glWidget = new GlRenderer(_emulationContext);
Application.Invoke(delegate
{
_viewBox.Remove(_gameTableWindow);
_gLWidget.Expand = true;
_viewBox.Child = _gLWidget;
_glWidget.Expand = true;
_viewBox.Child = _glWidget;
_gLWidget.ShowAll();
_glWidget.ShowAll();
EditFooterForGameRender();
});
_gLWidget.WaitEvent.WaitOne();
_glWidget.WaitEvent.WaitOne();
_gLWidget.Start();
_glWidget.Start();
device.Dispose();
_deviceExitStatus.Set();
@ -479,15 +473,15 @@ namespace Ryujinx.Ui
// NOTE: Everything that is here will not be executed when you close the UI.
Application.Invoke(delegate
{
_viewBox.Remove(_gLWidget);
_gLWidget.Exit();
_viewBox.Remove(_glWidget);
_glWidget.Exit();
if(_gLWidget.Window != this.Window && _gLWidget.Window != null)
if(_glWidget.Window != this.Window && _glWidget.Window != null)
{
_gLWidget.Window.Dispose();
_glWidget.Window.Dispose();
}
_gLWidget.Dispose();
_glWidget.Dispose();
_viewBox.Add(_gameTableWindow);
@ -497,7 +491,7 @@ namespace Ryujinx.Ui
_emulationContext = null;
_gameLoaded = false;
_gLWidget = null;
_glWidget = null;
DiscordIntegrationModule.SwitchToMainMenu();
@ -528,7 +522,7 @@ namespace Ryujinx.Ui
public void ToggleExtraWidgets(bool show)
{
if (_gLWidget != null)
if (_glWidget != null)
{
if (show)
{
@ -562,6 +556,11 @@ namespace Ryujinx.Ui
}
}
public static void SaveConfig()
{
ConfigurationState.Instance.ToFileFormat().SaveConfig(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
}
private void End(HLE.Switch device)
{
@ -580,10 +579,10 @@ namespace Ryujinx.Ui
{
UpdateGameMetadata(device.System.TitleIdText);
if (_gLWidget != null)
if (_glWidget != null)
{
// We tell the widget that we are exiting
_gLWidget.Exit();
_glWidget.Exit();
// Wait for the other thread to dispose the HLE context before exiting.
_deviceExitStatus.WaitOne();
@ -773,7 +772,7 @@ namespace Ryujinx.Ui
private void StopEmulation_Pressed(object sender, EventArgs args)
{
_gLWidget?.Exit();
_glWidget?.Exit();
}
private void Installer_File_Pressed(object o, EventArgs args)
@ -808,7 +807,7 @@ namespace Ryujinx.Ui
private void RefreshFirmwareLabel()
{
var currentFirmware = _contentManager.GetCurrentFirmwareVersion();
SystemVersion currentFirmware = _contentManager.GetCurrentFirmwareVersion();
GLib.Idle.Add(new GLib.IdleHandler(() =>
{
@ -830,7 +829,7 @@ namespace Ryujinx.Ui
fileChooser.Dispose();
var firmwareVersion = _contentManager.VerifyFirmwarePackage(filename);
SystemVersion firmwareVersion = _contentManager.VerifyFirmwarePackage(filename);
if (firmwareVersion == null)
{
@ -849,7 +848,7 @@ namespace Ryujinx.Ui
return;
}
var currentVersion = _contentManager.GetCurrentFirmwareVersion();
SystemVersion currentVersion = _contentManager.GetCurrentFirmwareVersion();
string dialogMessage = $"System version {firmwareVersion.VersionString} will be installed.";
@ -989,7 +988,7 @@ namespace Ryujinx.Ui
private void Settings_Pressed(object sender, EventArgs args)
{
SwitchSettings settingsWin = new SwitchSettings(_virtualFileSystem, _contentManager);
SettingsWindow settingsWin = new SettingsWindow(_virtualFileSystem, _contentManager);
settingsWin.Show();
}
@ -1205,10 +1204,5 @@ namespace Ryujinx.Ui
return 0;
}
}
public static void SaveConfig()
{
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
}
}
}

View File

@ -1,143 +0,0 @@
using OpenTK;
using OpenTK.Input;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE.HOS.Services.Hid;
using System;
using InnerNpadController = Ryujinx.Common.Configuration.Hid.NpadController;
namespace Ryujinx.Ui.Input
{
public class NpadController
{
private InnerNpadController _inner;
// NOTE: This should be initialized AFTER GTK for compat reasons with OpenTK SDL2 backend and GTK on Linux.
// BODY: Usage of Joystick.GetState must be defer to after GTK full initialization. Otherwise, GTK will segfault because SDL2 was already init *sighs*
public NpadController(InnerNpadController inner)
{
_inner = inner;
}
private bool IsEnabled()
{
return _inner.Enabled && Joystick.GetState(_inner.Index).IsConnected;
}
public ControllerKeys GetButtons()
{
if (!IsEnabled())
{
return 0;
}
JoystickState joystickState = Joystick.GetState(_inner.Index);
ControllerKeys buttons = 0;
if (IsActivated(joystickState, _inner.LeftJoycon.DPadUp)) buttons |= ControllerKeys.DpadUp;
if (IsActivated(joystickState, _inner.LeftJoycon.DPadDown)) buttons |= ControllerKeys.DpadDown;
if (IsActivated(joystickState, _inner.LeftJoycon.DPadLeft)) buttons |= ControllerKeys.DpadLeft;
if (IsActivated(joystickState, _inner.LeftJoycon.DPadRight)) buttons |= ControllerKeys.DpadRight;
if (IsActivated(joystickState, _inner.LeftJoycon.StickButton)) buttons |= ControllerKeys.LStick;
if (IsActivated(joystickState, _inner.LeftJoycon.ButtonMinus)) buttons |= ControllerKeys.Minus;
if (IsActivated(joystickState, _inner.LeftJoycon.ButtonL)) buttons |= ControllerKeys.L | ControllerKeys.Sl;
if (IsActivated(joystickState, _inner.LeftJoycon.ButtonZl)) buttons |= ControllerKeys.Zl;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonA)) buttons |= ControllerKeys.A;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonB)) buttons |= ControllerKeys.B;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonX)) buttons |= ControllerKeys.X;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonY)) buttons |= ControllerKeys.Y;
if (IsActivated(joystickState, _inner.RightJoycon.StickButton)) buttons |= ControllerKeys.RStick;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonPlus)) buttons |= ControllerKeys.Plus;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonR)) buttons |= ControllerKeys.R | ControllerKeys.Sr;
if (IsActivated(joystickState, _inner.RightJoycon.ButtonZr)) buttons |= ControllerKeys.Zr;
return buttons;
}
private bool IsActivated(JoystickState joystickState, ControllerInputId controllerInputId)
{
if (controllerInputId <= ControllerInputId.Button20)
{
return joystickState.IsButtonDown((int)controllerInputId);
}
else if (controllerInputId <= ControllerInputId.Axis5)
{
int axis = controllerInputId - ControllerInputId.Axis0;
return joystickState.GetAxis(axis) > _inner.TriggerThreshold;
}
else if (controllerInputId <= ControllerInputId.Hat2Right)
{
int hat = (controllerInputId - ControllerInputId.Hat0Up) / 4;
int baseHatId = (int)ControllerInputId.Hat0Up + (hat * 4);
JoystickHatState hatState = joystickState.GetHat((JoystickHat)hat);
if (hatState.IsUp && ((int)controllerInputId % baseHatId == 0)) return true;
if (hatState.IsDown && ((int)controllerInputId % baseHatId == 1)) return true;
if (hatState.IsLeft && ((int)controllerInputId % baseHatId == 2)) return true;
if (hatState.IsRight && ((int)controllerInputId % baseHatId == 3)) return true;
}
return false;
}
public (short, short) GetLeftStick()
{
if (!IsEnabled())
{
return (0, 0);
}
return GetStick(_inner.LeftJoycon.Stick);
}
public (short, short) GetRightStick()
{
if (!IsEnabled())
{
return (0, 0);
}
return GetStick(_inner.RightJoycon.Stick);
}
private (short, short) GetStick(ControllerInputId stickInputId)
{
if (stickInputId < ControllerInputId.Axis0 || stickInputId > ControllerInputId.Axis5)
{
return (0, 0);
}
JoystickState jsState = Joystick.GetState(_inner.Index);
int xAxis = stickInputId - ControllerInputId.Axis0;
float xValue = jsState.GetAxis(xAxis);
float yValue = 0 - jsState.GetAxis(xAxis + 1); // Invert Y-axis
return ApplyDeadzone(new Vector2(xValue, yValue));
}
private (short, short) ApplyDeadzone(Vector2 axis)
{
return (ClampAxis(MathF.Abs(axis.X) > _inner.Deadzone ? axis.X : 0f),
ClampAxis(MathF.Abs(axis.Y) > _inner.Deadzone ? axis.Y : 0f));
}
private static short ClampAxis(float value)
{
if (value <= -short.MaxValue)
{
return -short.MaxValue;
}
else
{
return (short)(value * short.MaxValue);
}
}
}
}

View File

@ -0,0 +1,58 @@
using Gtk;
using System;
using System.Reflection;
using GUI = Gtk.Builder.ObjectAttribute;
namespace Ryujinx.Ui
{
public class ProfileDialog : Dialog
{
public string FileName { get; private set; }
#pragma warning disable CS0649, IDE0044
[GUI] Entry _profileEntry;
[GUI] Label _errorMessage;
#pragma warning restore CS0649, IDE0044
public ProfileDialog() : this(new Builder("Ryujinx.Ui.ProfileDialog.glade")) { }
private ProfileDialog(Builder builder) : base(builder.GetObject("_profileDialog").Handle)
{
builder.Autoconnect(this);
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
}
private void OkToggle_Activated(object sender, EventArgs args)
{
((ToggleButton)sender).SetStateFlags(0, true);
bool validFileName = true;
foreach (char invalidChar in System.IO.Path.GetInvalidFileNameChars())
{
if (_profileEntry.Text.Contains(invalidChar))
{
validFileName = false;
}
}
if (validFileName && !string.IsNullOrEmpty(_profileEntry.Text))
{
FileName = $"{_profileEntry.Text}.json";
Respond(ResponseType.Ok);
}
else
{
_errorMessage.Text = "The file name contains invalid characters. Please try again.";
}
}
private void CancelToggle_Activated(object sender, EventArgs args)
{
Respond(ResponseType.Cancel);
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkDialog" id="_profileDialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Ryujinx - Profile Dialog</property>
<property name="modal">True</property>
<property name="window_position">center</property>
<property name="default_width">400</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkToggleButton" id="OkToggle">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="toggled" handler="OkToggle_Activated" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="CancelToggle">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="toggled" handler="CancelToggle_Activated" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">20</property>
<property name="margin_bottom">10</property>
<property name="label" translatable="yes">Enter a name for the new profile:</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="_profileEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">20</property>
<property name="margin_right">20</property>
<property name="margin_top">20</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="_errorMessage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_left">20</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<attributes>
<attribute name="foreground" value="#ffff00000000"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -0,0 +1,409 @@
using Gtk;
using Ryujinx.Configuration;
using Ryujinx.Configuration.System;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.HLE.FileSystem;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Ryujinx.Common.Configuration.Hid;
using GUI = Gtk.Builder.ObjectAttribute;
namespace Ryujinx.Ui
{
public class SettingsWindow : Window
{
private static ListStore _gameDirsBoxStore;
private static VirtualFileSystem _virtualFileSystem;
private long _systemTimeOffset;
#pragma warning disable CS0649, IDE0044
[GUI] CheckButton _errorLogToggle;
[GUI] CheckButton _warningLogToggle;
[GUI] CheckButton _infoLogToggle;
[GUI] CheckButton _stubLogToggle;
[GUI] CheckButton _debugLogToggle;
[GUI] CheckButton _fileLogToggle;
[GUI] CheckButton _guestLogToggle;
[GUI] CheckButton _fsAccessLogToggle;
[GUI] Adjustment _fsLogSpinAdjustment;
[GUI] CheckButton _dockedModeToggle;
[GUI] CheckButton _discordToggle;
[GUI] CheckButton _vSyncToggle;
[GUI] CheckButton _multiSchedToggle;
[GUI] CheckButton _fsicToggle;
[GUI] CheckButton _ignoreToggle;
[GUI] CheckButton _directKeyboardAccess;
[GUI] ComboBoxText _systemLanguageSelect;
[GUI] ComboBoxText _systemRegionSelect;
[GUI] ComboBoxText _systemTimeZoneSelect;
[GUI] SpinButton _systemTimeYearSpin;
[GUI] SpinButton _systemTimeMonthSpin;
[GUI] SpinButton _systemTimeDaySpin;
[GUI] SpinButton _systemTimeHourSpin;
[GUI] SpinButton _systemTimeMinuteSpin;
[GUI] Adjustment _systemTimeYearSpinAdjustment;
[GUI] Adjustment _systemTimeMonthSpinAdjustment;
[GUI] Adjustment _systemTimeDaySpinAdjustment;
[GUI] Adjustment _systemTimeHourSpinAdjustment;
[GUI] Adjustment _systemTimeMinuteSpinAdjustment;
[GUI] CheckButton _custThemeToggle;
[GUI] Entry _custThemePath;
[GUI] ToggleButton _browseThemePath;
[GUI] Label _custThemePathLabel;
[GUI] TreeView _gameDirsBox;
[GUI] Entry _addGameDirBox;
[GUI] Entry _graphicsShadersDumpPath;
[GUI] ComboBoxText _anisotropy;
[GUI] ToggleButton _configureController1;
[GUI] ToggleButton _configureController2;
[GUI] ToggleButton _configureController3;
[GUI] ToggleButton _configureController4;
[GUI] ToggleButton _configureController5;
[GUI] ToggleButton _configureController6;
[GUI] ToggleButton _configureController7;
[GUI] ToggleButton _configureController8;
[GUI] ToggleButton _configureControllerH;
#pragma warning restore CS0649, IDE0044
public SettingsWindow(VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(new Builder("Ryujinx.Ui.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
private SettingsWindow(Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
{
builder.Autoconnect(this);
this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
_virtualFileSystem = virtualFileSystem;
//Bind Events
_configureController1.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player1);
_configureController2.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player2);
_configureController3.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player3);
_configureController4.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player4);
_configureController5.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player5);
_configureController6.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player6);
_configureController7.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player7);
_configureController8.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player8);
_configureControllerH.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Handheld);
//Setup Currents
if (ConfigurationState.Instance.Logger.EnableFileLog)
{
_fileLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableError)
{
_errorLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableWarn)
{
_warningLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableInfo)
{
_infoLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableStub)
{
_stubLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableDebug)
{
_debugLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableGuest)
{
_guestLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableFsAccessLog)
{
_fsAccessLogToggle.Click();
}
if (ConfigurationState.Instance.System.EnableDockedMode)
{
_dockedModeToggle.Click();
}
if (ConfigurationState.Instance.EnableDiscordIntegration)
{
_discordToggle.Click();
}
if (ConfigurationState.Instance.Graphics.EnableVsync)
{
_vSyncToggle.Click();
}
if (ConfigurationState.Instance.System.EnableMulticoreScheduling)
{
_multiSchedToggle.Click();
}
if (ConfigurationState.Instance.System.EnableFsIntegrityChecks)
{
_fsicToggle.Click();
}
if (ConfigurationState.Instance.System.IgnoreMissingServices)
{
_ignoreToggle.Click();
}
if (ConfigurationState.Instance.Hid.EnableKeyboard)
{
_directKeyboardAccess.Click();
}
if (ConfigurationState.Instance.Ui.EnableCustomTheme)
{
_custThemeToggle.Click();
}
TimeZoneContentManager timeZoneContentManager = new TimeZoneContentManager();
timeZoneContentManager.InitializeInstance(virtualFileSystem, contentManager, LibHac.FsSystem.IntegrityCheckLevel.None);
List<string> locationNames = timeZoneContentManager.LocationNameCache.ToList();
locationNames.Sort();
foreach (string locationName in locationNames)
{
_systemTimeZoneSelect.Append(locationName, locationName);
}
_systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
_systemRegionSelect.SetActiveId(ConfigurationState.Instance.System.Region.Value.ToString());
_systemTimeZoneSelect.SetActiveId(timeZoneContentManager.SanityCheckDeviceLocationName());
_anisotropy.SetActiveId(ConfigurationState.Instance.Graphics.MaxAnisotropy.Value.ToString());
_custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath;
_graphicsShadersDumpPath.Buffer.Text = ConfigurationState.Instance.Graphics.ShadersDumpPath;
_fsLogSpinAdjustment.Value = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
_systemTimeOffset = ConfigurationState.Instance.System.SystemTimeOffset;
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
_gameDirsBoxStore = new ListStore(typeof(string));
_gameDirsBox.Model = _gameDirsBoxStore;
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
{
_gameDirsBoxStore.AppendValues(gameDir);
}
if (_custThemeToggle.Active == false)
{
_custThemePath.Sensitive = false;
_custThemePathLabel.Sensitive = false;
_browseThemePath.Sensitive = false;
}
//Setup system time spinners
UpdateSystemTimeSpinners();
}
private void UpdateSystemTimeSpinners()
{
//Bind system time events
_systemTimeYearSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeMonthSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeDaySpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeHourSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeMinuteSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
//Apply actual system time + SystemTimeOffset to system time spin buttons
DateTime systemTime = DateTime.Now.AddSeconds(_systemTimeOffset);
_systemTimeYearSpinAdjustment.Value = systemTime.Year;
_systemTimeMonthSpinAdjustment.Value = systemTime.Month;
_systemTimeDaySpinAdjustment.Value = systemTime.Day;
_systemTimeHourSpinAdjustment.Value = systemTime.Hour;
_systemTimeMinuteSpinAdjustment.Value = systemTime.Minute;
//Format spin buttons text to include leading zeros
_systemTimeYearSpin.Text = systemTime.Year.ToString("0000");
_systemTimeMonthSpin.Text = systemTime.Month.ToString("00");
_systemTimeDaySpin.Text = systemTime.Day.ToString("00");
_systemTimeHourSpin.Text = systemTime.Hour.ToString("00");
_systemTimeMinuteSpin.Text = systemTime.Minute.ToString("00");
//Bind system time events
_systemTimeYearSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeMonthSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeDaySpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeHourSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeMinuteSpin.ValueChanged += SystemTimeSpin_ValueChanged;
}
//Events
private void SystemTimeSpin_ValueChanged(Object sender, EventArgs e)
{
int year = _systemTimeYearSpin.ValueAsInt;
int month = _systemTimeMonthSpin.ValueAsInt;
int day = _systemTimeDaySpin.ValueAsInt;
int hour = _systemTimeHourSpin.ValueAsInt;
int minute = _systemTimeMinuteSpin.ValueAsInt;
if (!DateTime.TryParse(year + "-" + month + "-" + day + " " + hour + ":" + minute, out DateTime newTime))
{
UpdateSystemTimeSpinners();
return;
}
newTime = newTime.AddSeconds(DateTime.Now.Second).AddMilliseconds(DateTime.Now.Millisecond);
long systemTimeOffset = (long)Math.Ceiling((newTime - DateTime.Now).TotalMinutes) * 60L;
if (_systemTimeOffset != systemTimeOffset)
{
_systemTimeOffset = systemTimeOffset;
UpdateSystemTimeSpinners();
}
}
private void AddDir_Pressed(object sender, EventArgs args)
{
if (Directory.Exists(_addGameDirBox.Buffer.Text))
{
_gameDirsBoxStore.AppendValues(_addGameDirBox.Buffer.Text);
}
else
{
FileChooserDialog fileChooser = new FileChooserDialog("Choose the game directory to add to the list", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Add", ResponseType.Accept);
if (fileChooser.Run() == (int)ResponseType.Accept)
{
_gameDirsBoxStore.AppendValues(fileChooser.Filename);
}
fileChooser.Dispose();
}
_addGameDirBox.Buffer.Text = "";
((ToggleButton)sender).SetStateFlags(0, true);
}
private void RemoveDir_Pressed(object sender, EventArgs args)
{
TreeSelection selection = _gameDirsBox.Selection;
if (selection.GetSelected(out TreeIter treeIter))
{
_gameDirsBoxStore.Remove(ref treeIter);
}
((ToggleButton)sender).SetStateFlags(0, true);
}
private void CustThemeToggle_Activated(object sender, EventArgs args)
{
_custThemePath.Sensitive = _custThemeToggle.Active;
_custThemePathLabel.Sensitive = _custThemeToggle.Active;
_browseThemePath.Sensitive = _custThemeToggle.Active;
}
private void BrowseThemeDir_Pressed(object sender, EventArgs args)
{
FileChooserDialog fileChooser = new FileChooserDialog("Choose the theme to load", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept);
fileChooser.Filter = new FileFilter();
fileChooser.Filter.AddPattern("*.css");
if (fileChooser.Run() == (int)ResponseType.Accept)
{
_custThemePath.Buffer.Text = fileChooser.Filename;
}
fileChooser.Dispose();
_browseThemePath.SetStateFlags(0, true);
}
private void OpenLogsFolder_Pressed(object sender, EventArgs args)
{
string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
DirectoryInfo directory = new DirectoryInfo(logPath);
directory.Create();
Process.Start(new ProcessStartInfo()
{
FileName = logPath,
UseShellExecute = true,
Verb = "open"
});
}
private void ConfigureController_Pressed(object sender, EventArgs args, PlayerIndex playerIndex)
{
((ToggleButton)sender).SetStateFlags(0, true);
ControllerWindow controllerWin = new ControllerWindow(playerIndex, _virtualFileSystem);
controllerWin.Show();
}
private void SaveToggle_Activated(object sender, EventArgs args)
{
List<string> gameDirs = new List<string>();
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
for (int i = 0; i < _gameDirsBoxStore.IterNChildren(); i++)
{
gameDirs.Add((string)_gameDirsBoxStore.GetValue(treeIter, 0));
_gameDirsBoxStore.IterNext(ref treeIter);
}
ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active;
ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active;
ConfigurationState.Instance.Logger.EnableInfo.Value = _infoLogToggle.Active;
ConfigurationState.Instance.Logger.EnableStub.Value = _stubLogToggle.Active;
ConfigurationState.Instance.Logger.EnableDebug.Value = _debugLogToggle.Active;
ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active;
ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active;
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
ConfigurationState.Instance.System.EnableMulticoreScheduling.Value = _multiSchedToggle.Active;
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Configuration.System.Region>(_systemRegionSelect.ActiveId);
ConfigurationState.Instance.System.TimeZone.Value = _systemTimeZoneSelect.ActiveId;
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs;
ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value;
ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId);
MainWindow.SaveConfig();
MainWindow.ApplyTheme();
MainWindow.UpdateGameTable();
Dispose();
}
private void CloseToggle_Activated(object sender, EventArgs args)
{
Dispose();
}
}
}

View File

@ -1,611 +0,0 @@
using Gtk;
using Ryujinx.Configuration;
using Ryujinx.Configuration.Hid;
using Ryujinx.Configuration.System;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using GUI = Gtk.Builder.ObjectAttribute;
namespace Ryujinx.Ui
{
public class SwitchSettings : Window
{
private static ListStore _gameDirsBoxStore;
private static bool _listeningForKeypress;
private long _systemTimeOffset;
#pragma warning disable CS0649
#pragma warning disable IDE0044
[GUI] Window _settingsWin;
[GUI] CheckButton _errorLogToggle;
[GUI] CheckButton _warningLogToggle;
[GUI] CheckButton _infoLogToggle;
[GUI] CheckButton _stubLogToggle;
[GUI] CheckButton _debugLogToggle;
[GUI] CheckButton _fileLogToggle;
[GUI] CheckButton _guestLogToggle;
[GUI] CheckButton _fsAccessLogToggle;
[GUI] Adjustment _fsLogSpinAdjustment;
[GUI] CheckButton _dockedModeToggle;
[GUI] CheckButton _discordToggle;
[GUI] CheckButton _vSyncToggle;
[GUI] CheckButton _multiSchedToggle;
[GUI] CheckButton _fsicToggle;
[GUI] CheckButton _ignoreToggle;
[GUI] CheckButton _directKeyboardAccess;
[GUI] ComboBoxText _systemLanguageSelect;
[GUI] ComboBoxText _systemRegionSelect;
[GUI] ComboBoxText _systemTimeZoneSelect;
[GUI] SpinButton _systemTimeYearSpin;
[GUI] SpinButton _systemTimeMonthSpin;
[GUI] SpinButton _systemTimeDaySpin;
[GUI] SpinButton _systemTimeHourSpin;
[GUI] SpinButton _systemTimeMinuteSpin;
[GUI] Adjustment _systemTimeYearSpinAdjustment;
[GUI] Adjustment _systemTimeMonthSpinAdjustment;
[GUI] Adjustment _systemTimeDaySpinAdjustment;
[GUI] Adjustment _systemTimeHourSpinAdjustment;
[GUI] Adjustment _systemTimeMinuteSpinAdjustment;
[GUI] CheckButton _custThemeToggle;
[GUI] Entry _custThemePath;
[GUI] ToggleButton _browseThemePath;
[GUI] Label _custThemePathLabel;
[GUI] TreeView _gameDirsBox;
[GUI] Entry _addGameDirBox;
[GUI] ToggleButton _addDir;
[GUI] ToggleButton _browseDir;
[GUI] ToggleButton _removeDir;
[GUI] Entry _graphicsShadersDumpPath;
[GUI] ComboBoxText _anisotropy;
[GUI] Image _controller1Image;
[GUI] ComboBoxText _controller1Type;
[GUI] ToggleButton _lStickUp1;
[GUI] ToggleButton _lStickDown1;
[GUI] ToggleButton _lStickLeft1;
[GUI] ToggleButton _lStickRight1;
[GUI] ToggleButton _lStickButton1;
[GUI] ToggleButton _dpadUp1;
[GUI] ToggleButton _dpadDown1;
[GUI] ToggleButton _dpadLeft1;
[GUI] ToggleButton _dpadRight1;
[GUI] ToggleButton _minus1;
[GUI] ToggleButton _l1;
[GUI] ToggleButton _zL1;
[GUI] ToggleButton _rStickUp1;
[GUI] ToggleButton _rStickDown1;
[GUI] ToggleButton _rStickLeft1;
[GUI] ToggleButton _rStickRight1;
[GUI] ToggleButton _rStickButton1;
[GUI] ToggleButton _a1;
[GUI] ToggleButton _b1;
[GUI] ToggleButton _x1;
[GUI] ToggleButton _y1;
[GUI] ToggleButton _plus1;
[GUI] ToggleButton _r1;
[GUI] ToggleButton _zR1;
#pragma warning restore CS0649
#pragma warning restore IDE0044
public SwitchSettings(HLE.FileSystem.VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(new Builder("Ryujinx.Ui.SwitchSettings.glade"), virtualFileSystem, contentManager) { }
private SwitchSettings(Builder builder, HLE.FileSystem.VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
{
builder.Autoconnect(this);
_settingsWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
_controller1Image.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyCon.png", 500, 500);
//Bind Events
_lStickUp1.Clicked += (sender, args) => Button_Pressed(sender, args, _lStickUp1);
_lStickDown1.Clicked += (sender, args) => Button_Pressed(sender, args, _lStickDown1);
_lStickLeft1.Clicked += (sender, args) => Button_Pressed(sender, args, _lStickLeft1);
_lStickRight1.Clicked += (sender, args) => Button_Pressed(sender, args, _lStickRight1);
_lStickButton1.Clicked += (sender, args) => Button_Pressed(sender, args, _lStickButton1);
_dpadUp1.Clicked += (sender, args) => Button_Pressed(sender, args, _dpadUp1);
_dpadDown1.Clicked += (sender, args) => Button_Pressed(sender, args, _dpadDown1);
_dpadLeft1.Clicked += (sender, args) => Button_Pressed(sender, args, _dpadLeft1);
_dpadRight1.Clicked += (sender, args) => Button_Pressed(sender, args, _dpadRight1);
_minus1.Clicked += (sender, args) => Button_Pressed(sender, args, _minus1);
_l1.Clicked += (sender, args) => Button_Pressed(sender, args, _l1);
_zL1.Clicked += (sender, args) => Button_Pressed(sender, args, _zL1);
_rStickUp1.Clicked += (sender, args) => Button_Pressed(sender, args, _rStickUp1);
_rStickDown1.Clicked += (sender, args) => Button_Pressed(sender, args, _rStickDown1);
_rStickLeft1.Clicked += (sender, args) => Button_Pressed(sender, args, _rStickLeft1);
_rStickRight1.Clicked += (sender, args) => Button_Pressed(sender, args, _rStickRight1);
_rStickButton1.Clicked += (sender, args) => Button_Pressed(sender, args, _rStickButton1);
_a1.Clicked += (sender, args) => Button_Pressed(sender, args, _a1);
_b1.Clicked += (sender, args) => Button_Pressed(sender, args, _b1);
_x1.Clicked += (sender, args) => Button_Pressed(sender, args, _x1);
_y1.Clicked += (sender, args) => Button_Pressed(sender, args, _y1);
_plus1.Clicked += (sender, args) => Button_Pressed(sender, args, _plus1);
_r1.Clicked += (sender, args) => Button_Pressed(sender, args, _r1);
_zR1.Clicked += (sender, args) => Button_Pressed(sender, args, _zR1);
_controller1Type.Changed += (sender, args) => Controller_Changed(sender, args, _controller1Type.ActiveId, _controller1Image);
//Setup Currents
if (ConfigurationState.Instance.Logger.EnableFileLog)
{
_fileLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableError)
{
_errorLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableWarn)
{
_warningLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableInfo)
{
_infoLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableStub)
{
_stubLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableDebug)
{
_debugLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableGuest)
{
_guestLogToggle.Click();
}
if (ConfigurationState.Instance.Logger.EnableFsAccessLog)
{
_fsAccessLogToggle.Click();
}
if (ConfigurationState.Instance.System.EnableDockedMode)
{
_dockedModeToggle.Click();
}
if (ConfigurationState.Instance.EnableDiscordIntegration)
{
_discordToggle.Click();
}
if (ConfigurationState.Instance.Graphics.EnableVsync)
{
_vSyncToggle.Click();
}
if (ConfigurationState.Instance.System.EnableMulticoreScheduling)
{
_multiSchedToggle.Click();
}
if (ConfigurationState.Instance.System.EnableFsIntegrityChecks)
{
_fsicToggle.Click();
}
if (ConfigurationState.Instance.System.IgnoreMissingServices)
{
_ignoreToggle.Click();
}
if (ConfigurationState.Instance.Hid.EnableKeyboard)
{
_directKeyboardAccess.Click();
}
if (ConfigurationState.Instance.Ui.EnableCustomTheme)
{
_custThemeToggle.Click();
}
TimeZoneContentManager timeZoneContentManager = new TimeZoneContentManager();
timeZoneContentManager.InitializeInstance(virtualFileSystem, contentManager, LibHac.FsSystem.IntegrityCheckLevel.None);
List<string> locationNames = timeZoneContentManager.LocationNameCache.ToList();
locationNames.Sort();
foreach (string locationName in locationNames)
{
_systemTimeZoneSelect.Append(locationName, locationName);
}
_systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
_systemRegionSelect .SetActiveId(ConfigurationState.Instance.System.Region.Value.ToString());
_systemTimeZoneSelect.SetActiveId(timeZoneContentManager.SanityCheckDeviceLocationName());
_anisotropy .SetActiveId(ConfigurationState.Instance.Graphics.MaxAnisotropy.Value.ToString());
_controller1Type .SetActiveId(ConfigurationState.Instance.Hid.ControllerType.Value.ToString());
Controller_Changed(null, null, _controller1Type.ActiveId, _controller1Image);
_lStickUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickUp.ToString();
_lStickDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickDown.ToString();
_lStickLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickLeft.ToString();
_lStickRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickRight.ToString();
_lStickButton1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickButton.ToString();
_dpadUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadUp.ToString();
_dpadDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadDown.ToString();
_dpadLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadLeft.ToString();
_dpadRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadRight.ToString();
_minus1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonMinus.ToString();
_l1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonL.ToString();
_zL1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonZl.ToString();
_rStickUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickUp.ToString();
_rStickDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickDown.ToString();
_rStickLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickLeft.ToString();
_rStickRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickRight.ToString();
_rStickButton1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickButton.ToString();
_a1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonA.ToString();
_b1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonB.ToString();
_x1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonX.ToString();
_y1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonY.ToString();
_plus1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonPlus.ToString();
_r1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonR.ToString();
_zR1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonZr.ToString();
_custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath;
_graphicsShadersDumpPath.Buffer.Text = ConfigurationState.Instance.Graphics.ShadersDumpPath;
_fsLogSpinAdjustment.Value = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
_systemTimeOffset = ConfigurationState.Instance.System.SystemTimeOffset;
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
_gameDirsBoxStore = new ListStore(typeof(string));
_gameDirsBox.Model = _gameDirsBoxStore;
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
{
_gameDirsBoxStore.AppendValues(gameDir);
}
if (_custThemeToggle.Active == false)
{
_custThemePath.Sensitive = false;
_custThemePathLabel.Sensitive = false;
_browseThemePath.Sensitive = false;
}
_listeningForKeypress = false;
//Setup system time spinners
UpdateSystemTimeSpinners();
}
private void UpdateSystemTimeSpinners()
{
//Unbind system time spin events
_systemTimeYearSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeMonthSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeDaySpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeHourSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
_systemTimeMinuteSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
//Apply actual system time + SystemTimeOffset to system time spin buttons
DateTime systemTime = DateTime.Now.AddSeconds(_systemTimeOffset);
_systemTimeYearSpinAdjustment.Value = systemTime.Year;
_systemTimeMonthSpinAdjustment.Value = systemTime.Month;
_systemTimeDaySpinAdjustment.Value = systemTime.Day;
_systemTimeHourSpinAdjustment.Value = systemTime.Hour;
_systemTimeMinuteSpinAdjustment.Value = systemTime.Minute;
//Format spin buttons text to include leading zeros
_systemTimeYearSpin.Text = systemTime.Year.ToString("0000");
_systemTimeMonthSpin.Text = systemTime.Month.ToString("00");
_systemTimeDaySpin.Text = systemTime.Day.ToString("00");
_systemTimeHourSpin.Text = systemTime.Hour.ToString("00");
_systemTimeMinuteSpin.Text = systemTime.Minute.ToString("00");
//Bind system time spin button events
_systemTimeYearSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeMonthSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeDaySpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeHourSpin.ValueChanged += SystemTimeSpin_ValueChanged;
_systemTimeMinuteSpin.ValueChanged += SystemTimeSpin_ValueChanged;
}
//Events
private void SystemTimeSpin_ValueChanged(Object sender, EventArgs e)
{
int year = _systemTimeYearSpin.ValueAsInt;
int month = _systemTimeMonthSpin.ValueAsInt;
int day = _systemTimeDaySpin.ValueAsInt;
int hour = _systemTimeHourSpin.ValueAsInt;
int minute = _systemTimeMinuteSpin.ValueAsInt;
if (!DateTime.TryParse(year + "-" + month + "-" + day + " " + hour + ":" + minute, out DateTime newTime))
{
UpdateSystemTimeSpinners();
return;
}
newTime = newTime.AddSeconds(DateTime.Now.Second).AddMilliseconds(DateTime.Now.Millisecond);
long systemTimeOffset = (long)Math.Ceiling((newTime - DateTime.Now).TotalMinutes) * 60L;
if (_systemTimeOffset != systemTimeOffset)
{
_systemTimeOffset = systemTimeOffset;
UpdateSystemTimeSpinners();
}
}
private void Button_Pressed(object sender, EventArgs args, ToggleButton button)
{
if (_listeningForKeypress == false)
{
KeyPressEvent += On_KeyPress;
_listeningForKeypress = true;
void On_KeyPress(object o, KeyPressEventArgs keyPressed)
{
string key = keyPressed.Event.Key.ToString();
string capKey = key.First().ToString().ToUpper() + key.Substring(1);
if (Enum.IsDefined(typeof(Configuration.Hid.Key), capKey))
{
button.Label = capKey;
}
else if (GdkToOpenTkInput.ContainsKey(key))
{
button.Label = GdkToOpenTkInput[key];
}
else
{
button.Label = "Space";
}
button.SetStateFlags(0, true);
KeyPressEvent -= On_KeyPress;
_listeningForKeypress = false;
}
}
else
{
button.SetStateFlags(0, true);
}
}
private void Controller_Changed(object sender, EventArgs args, string controllerType, Image controllerImage)
{
switch (controllerType)
{
case "ProController":
controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ProCon.png", 500, 500);
break;
case "NpadLeft":
controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.BlueCon.png", 500, 500);
break;
case "NpadRight":
controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RedCon.png", 500, 500);
break;
default:
controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyCon.png", 500, 500);
break;
}
}
private void AddDir_Pressed(object sender, EventArgs args)
{
if (Directory.Exists(_addGameDirBox.Buffer.Text))
{
_gameDirsBoxStore.AppendValues(_addGameDirBox.Buffer.Text);
}
_addDir.SetStateFlags(0, true);
}
private void BrowseDir_Pressed(object sender, EventArgs args)
{
FileChooserDialog fileChooser = new FileChooserDialog("Choose the game directory to add to the list", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Add", ResponseType.Accept);
if (fileChooser.Run() == (int)ResponseType.Accept)
{
_gameDirsBoxStore.AppendValues(fileChooser.Filename);
}
fileChooser.Dispose();
_browseDir.SetStateFlags(0, true);
}
private void RemoveDir_Pressed(object sender, EventArgs args)
{
TreeSelection selection = _gameDirsBox.Selection;
selection.GetSelected(out TreeIter treeIter);
_gameDirsBoxStore.Remove(ref treeIter);
_removeDir.SetStateFlags(0, true);
}
private void CustThemeToggle_Activated(object sender, EventArgs args)
{
_custThemePath.Sensitive = _custThemeToggle.Active;
_custThemePathLabel.Sensitive = _custThemeToggle.Active;
_browseThemePath.Sensitive = _custThemeToggle.Active;
}
private void BrowseThemeDir_Pressed(object sender, EventArgs args)
{
FileChooserDialog fileChooser = new FileChooserDialog("Choose the theme to load", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept);
fileChooser.Filter = new FileFilter();
fileChooser.Filter.AddPattern("*.css");
if (fileChooser.Run() == (int)ResponseType.Accept)
{
_custThemePath.Buffer.Text = fileChooser.Filename;
}
fileChooser.Dispose();
_browseThemePath.SetStateFlags(0, true);
}
private void OpenLogsFolder_Pressed(object sender, EventArgs args)
{
string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
DirectoryInfo directory = new DirectoryInfo(logPath);
directory.Create();
Process.Start(new ProcessStartInfo()
{
FileName = logPath,
UseShellExecute = true,
Verb = "open"
});
}
private void SaveToggle_Activated(object sender, EventArgs args)
{
List<string> gameDirs = new List<string>();
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
for (int i = 0; i < _gameDirsBoxStore.IterNChildren(); i++)
{
_gameDirsBoxStore.GetValue(treeIter, i);
gameDirs.Add((string)_gameDirsBoxStore.GetValue(treeIter, 0));
_gameDirsBoxStore.IterNext(ref treeIter);
}
ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active;
ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active;
ConfigurationState.Instance.Logger.EnableInfo.Value = _infoLogToggle.Active;
ConfigurationState.Instance.Logger.EnableStub.Value = _stubLogToggle.Active;
ConfigurationState.Instance.Logger.EnableDebug.Value = _debugLogToggle.Active;
ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active;
ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active;
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
ConfigurationState.Instance.System.EnableMulticoreScheduling.Value = _multiSchedToggle.Active;
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon = new NpadKeyboardLeft()
{
StickUp = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _lStickUp1.Label),
StickDown = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _lStickDown1.Label),
StickLeft = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _lStickLeft1.Label),
StickRight = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _lStickRight1.Label),
StickButton = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _lStickButton1.Label),
DPadUp = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _dpadUp1.Label),
DPadDown = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _dpadDown1.Label),
DPadLeft = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _dpadLeft1.Label),
DPadRight = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _dpadRight1.Label),
ButtonMinus = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _minus1.Label),
ButtonL = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _l1.Label),
ButtonZl = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _zL1.Label),
};
ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon = new NpadKeyboardRight()
{
StickUp = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _rStickUp1.Label),
StickDown = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _rStickDown1.Label),
StickLeft = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _rStickLeft1.Label),
StickRight = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _rStickRight1.Label),
StickButton = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _rStickButton1.Label),
ButtonA = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _a1.Label),
ButtonB = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _b1.Label),
ButtonX = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _x1.Label),
ButtonY = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _y1.Label),
ButtonPlus = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _plus1.Label),
ButtonR = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _r1.Label),
ButtonZr = (Configuration.Hid.Key)Enum.Parse(typeof(Configuration.Hid.Key), _zR1.Label),
};
ConfigurationState.Instance.System.Language.Value = (Language)Enum.Parse(typeof(Language), _systemLanguageSelect.ActiveId);
ConfigurationState.Instance.System.Region.Value = (Configuration.System.Region)Enum.Parse(typeof(Configuration.System.Region), _systemRegionSelect.ActiveId);
ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId);
ConfigurationState.Instance.Hid.ControllerType.Value = (ControllerType)Enum.Parse(typeof(ControllerType), _controller1Type.ActiveId);
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs;
ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value;
ConfigurationState.Instance.System.TimeZone.Value = _systemTimeZoneSelect.ActiveId;
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
MainWindow.SaveConfig();
MainWindow.ApplyTheme();
MainWindow.UpdateGameTable();
Dispose();
}
private void CloseToggle_Activated(object sender, EventArgs args)
{
Dispose();
}
public readonly Dictionary<string, string> GdkToOpenTkInput = new Dictionary<string, string>()
{
{ "Key_0", "Number0" },
{ "Key_1", "Number1" },
{ "Key_2", "Number2" },
{ "Key_3", "Number3" },
{ "Key_4", "Number4" },
{ "Key_5", "Number5" },
{ "Key_6", "Number6" },
{ "Key_7", "Number7" },
{ "Key_8", "Number8" },
{ "Key_9", "Number9" },
{ "equal", "Plus" },
{ "uparrow", "Up" },
{ "downarrow", "Down" },
{ "leftarrow", "Left" },
{ "rightarrow", "Right" },
{ "Control_L", "ControlLeft" },
{ "Control_R", "ControlRight" },
{ "Shift_L", "ShiftLeft" },
{ "Shift_R", "ShiftRight" },
{ "Alt_L", "AltLeft" },
{ "Alt_R", "AltRight" },
{ "Page_Up", "PageUp" },
{ "Page_Down", "PageDown" },
{ "KP_Enter", "KeypadEnter" },
{ "KP_Up", "Up" },
{ "KP_Down", "Down" },
{ "KP_Left", "Left" },
{ "KP_Right", "Right" },
{ "KP_Divide", "KeypadDivide" },
{ "KP_Multiply", "KeypadMultiply" },
{ "KP_Subtract", "KeypadSubtract" },
{ "KP_Add", "KeypadAdd" },
{ "KP_Decimal", "KeypadDecimal" },
{ "KP_0", "Keypad0" },
{ "KP_1", "Keypad1" },
{ "KP_2", "Keypad2" },
{ "KP_3", "Keypad3" },
{ "KP_4", "Keypad4" },
{ "KP_5", "Keypad5" },
{ "KP_6", "Keypad6" },
{ "KP_7", "Keypad7" },
{ "KP_8", "Keypad8" },
{ "KP_9", "Keypad9" },
};
}
}

View File

@ -133,7 +133,7 @@ namespace Ryujinx.Ui
if (showErrorDialog)
{
GtkDialog.CreateDialog("Ryujinx - Error", "Add Update Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
}
break;
@ -144,7 +144,7 @@ namespace Ryujinx.Ui
if (showErrorDialog)
{
GtkDialog.CreateDialog("Ryujinx - Error", "Add Update Failed!", $"Your key set is missing a key with the name: {exception.Name}");
GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", $"Your key set is missing a key with the name: {exception.Name}");
}
break;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000.8 1000" style="enable-background:new 0 0 1000.8 1000;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.1;}
.st1{fill:#02C5E5;}
.st2{fill:#FFFFFF;}
</style>
<g class="st0">
<path class="st1" d="M419.1,642.6v67.6c0,3.3-2.7,6-6,6h-4.2v-79.5h4.2C416.4,636.6,419.1,639.3,419.1,642.6z"/>
<path class="st1" d="M419.1,239.8v67.6c0,3.3-2.7,6-6,6h-4.2v-79.5h4.2C416.4,233.9,419.1,236.5,419.1,239.8z"/>
<path class="st1" d="M330.1,7v2.6h-54.2c-84.8,0-161.4,50.7-194.6,128.7l-3.4-3.4c-1.8-1.7-2.3-4.4-1.3-6.6
C111.2,50.8,188.1,1,272.9,1h51.2C327.4,1,330.1,3.7,330.1,7z"/>
<path class="st1" d="M359.6,115.1h-46.9c-1.6,0-3-1.3-3-3v-11.7c0-1.6,1.3-3,3-3h46.9c1.6,0,3,1.3,3,3v11.7
C362.6,113.8,361.3,115.1,359.6,115.1z"/>
<circle class="st1" cx="237.9" cy="464.4" r="37.5"/>
<circle class="st1" cx="237.9" cy="611.3" r="37.5"/>
<circle class="st1" cx="311.4" cy="537.9" r="37.5"/>
<ellipse class="st1" cx="164.5" cy="537.9" rx="37.5" ry="37.5"/>
<path class="st1" d="M269.1,689.9h45c4.9,0,8.9,4,8.9,8.9v45c0,4.9-4,8.9-8.9,8.9h-45c-4.9,0-8.9-4-8.9-8.9v-45
C260.2,693.9,264.2,689.9,269.1,689.9z"/>
<circle class="st1" cx="291.6" cy="721.3" r="19.4"/>
<path class="st1" d="M234.6,187.1v12.3c0,3-2.2,5.5-5.2,5.9c-25.2,3.7-45,23.5-48.7,48.7c-0.4,2.9-2.9,5.1-5.9,5.2h-12.3
C164.3,220.1,195.5,188.9,234.6,187.1z"/>
<path class="st1" d="M234.6,325.6v12.3c-39.1-1.7-70.3-33-72.1-72h12.3c3,0,5.5,2.2,5.9,5.2c3.7,25.2,23.5,45,48.7,48.7
C232.4,320.1,234.6,322.6,234.6,325.6z"/>
<path class="st1" d="M313.3,265.9c-1.7,39.1-33,70.3-72.1,72v-12.3c0-3,2.2-5.5,5.2-5.9c25.2-3.7,45-23.5,48.7-48.7
c0.4-2.9,2.9-5.1,5.9-5.2L313.3,265.9z"/>
<path class="st1" d="M313.3,259.2H301c-3,0-5.5-2.2-5.9-5.2c-3.7-25.2-23.5-45-48.7-48.7c-2.9-0.4-5.1-2.9-5.2-5.9v-12.3
C280.3,188.9,311.6,220.1,313.3,259.2z"/>
<path class="st1" d="M313.4,262.5c0,1.1,0,2.2-0.1,3.3H301c-3,0-5.5,2.2-5.9,5.2c-3.7,25.2-23.5,45-48.7,48.7
c-2.9,0.4-5.1,2.9-5.2,5.9v12.3c-1.1,0.1-2.2,0.1-3.3,0.1s-2.2,0-3.3-0.1v-12.3c0-3-2.2-5.5-5.2-5.9c-25.2-3.7-45-23.5-48.7-48.7
c-0.4-2.9-2.9-5.1-5.9-5.2h-12.3c-0.1-1.1-0.1-2.2-0.1-3.3s0-2.2,0.1-3.3h12.3c3,0,5.5-2.2,5.9-5.2c3.7-25.2,23.5-45,48.7-48.7
c2.9-0.4,5.1-2.9,5.2-5.9v-12.3c1.1-0.1,2.2-0.1,3.3-0.1s2.2,0,3.3,0.1v12.3c0,3,2.2,5.5,5.2,5.9c25.2,3.7,45,23.5,48.7,48.7
c0.4,2.9,2.9,5.1,5.9,5.2h12.3C313.4,260.3,313.4,261.4,313.4,262.5z"/>
</g>
<path class="st2" d="M413.1,906.6h-7.9c-3.6,0-6.4-2.9-6.5-6.5V71.2c0-3.6,2.9-6.4,6.5-6.5h7.9c3.6,0,6.4,2.9,6.5,6.5V207
c0,4.9-1.2,9.6-3.4,14l-6.7,13v79.2l6.7,13c2.2,4.3,3.4,9.1,3.4,13.9v269.7c0,4.9-1.2,9.6-3.4,14l-6.7,13V716l6.7,13
c2.2,4.3,3.4,9.1,3.4,13.9v157.2C419.6,903.7,416.7,906.6,413.1,906.6z M405.2,65.7c-3,0-5.5,2.4-5.5,5.5v828.9c0,3,2.4,5.5,5.5,5.5
h7.9c3,0,5.5-2.4,5.5-5.5V742.9c0-4.7-1.1-9.3-3.3-13.5l-6.8-13.1c0-0.1-0.1-0.2-0.1-0.2v-79.5c0-0.1,0-0.2,0.1-0.2l6.8-13.1
c2.2-4.2,3.3-8.8,3.3-13.5V340.1c0-4.7-1.1-9.3-3.3-13.5l-6.8-13.1c0-0.1-0.1-0.2-0.1-0.2v-79.5c0-0.1,0-0.2,0.1-0.2l6.8-13.1
c2.2-4.2,3.3-8.8,3.3-13.5V71.2c0-3-2.4-5.5-5.5-5.5H405.2z"/>
<path class="st2" d="M399.3,858.9h-11.2c-0.3,0-0.5-0.2-0.5-0.5V72c0-0.3,0.2-0.5,0.5-0.5h11.2c0.3,0,0.5,0.2,0.5,0.5v786.4
C399.8,858.7,399.6,858.9,399.3,858.9z M388.6,857.9h10.2V72.5h-10.2V857.9z"/>
<path class="st2" d="M382.1,1000H275.9C158.9,1000,64,905.2,64,788.1l0,0V220.9C64,104.1,159.1,9.1,275.9,9.1h106.2
c3.6,0,6.5,2.9,6.5,6.5v978C388.6,997.1,385.7,1000,382.1,1000z M275.9,10.1C159.6,10.1,65,104.7,65,220.9v567.2
C65,904.4,159.6,999,275.9,999h106.2c3,0,5.5-2.4,5.5-5.5v-978c0-3-2.4-5.5-5.5-5.5H275.9V10.1z"/>
<polygon class="st1" points="237.9,448.9 225.8,469.9 250,469.9 "/>
<polygon class="st1" points="237.9,626.9 225.8,605.9 250,605.9 "/>
<polygon class="st1" points="148.9,537.9 169.9,550 169.9,525.8 "/>
<polygon class="st1" points="326.9,537.9 305.9,550 305.9,525.8 "/>
<path class="st1" d="M413.1,717.1h-4.2c-0.6,0-1-0.4-1-1l0,0v-79.5c0-0.6,0.4-1,1-1l0,0h4.2c3.8,0,6.9,3.1,7,7v67.6
C420.1,714,417,717.1,413.1,717.1z M409.9,715.1h3.2c2.7,0,5-2.2,5-5v-67.6c0-2.7-2.2-5-5-5h-3.2V715.1z"/>
<path class="st1" d="M413.1,314.3h-4.2c-0.6,0-1-0.4-1-1v-79.5c0-0.6,0.4-1,1-1h4.2c3.8,0,6.9,3.1,7,7v67.6
C420.1,311.2,417,314.3,413.1,314.3z M409.9,312.3h3.2c2.7,0,5-2.2,5-5v-67.6c0-2.7-2.2-5-5-5h-3.2V312.3z"/>
<path class="st1" d="M81.3,139.3c-0.3,0-0.5-0.1-0.7-0.3l-3.4-3.4c-2-2-2.6-5.1-1.5-7.8C110.5,50.1,187.7,0.1,272.9,0h51.2
c3.8,0,6.9,3.1,7,7v2.6c0,0.6-0.4,1-1,1h-54.2C191.4,10.5,115.1,61,82.2,138.7c-0.1,0.3-0.4,0.5-0.7,0.6
C81.4,139.3,81.3,139.3,81.3,139.3z M272.9,2C188.5,2.1,112,51.7,77.5,128.7c-0.8,1.9-0.4,4.1,1.1,5.5l2.4,2.4
C114.6,58.8,191.3,8.5,276,8.6h53.2V7c0-2.7-2.2-5-5-5H272.9z"/>
<path class="st1" d="M359.6,116.1h-46.9c-2.2,0-4-1.8-4-4v-11.7c0-2.2,1.8-4,4-4h46.9c2.2,0,4,1.8,4,4v11.7
C363.6,114.3,361.8,116.1,359.6,116.1z M312.7,98.5c-1.1,0-2,0.9-2,2v11.7c0,1.1,0.9,2,2,2h46.9c1.1,0,2-0.9,2-2v-11.7
c0-1.1-0.9-2-2-2H312.7z"/>
<path class="st1" d="M237.9,502.9c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C276.4,485.7,259.2,502.9,237.9,502.9z M237.9,428c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5S258.1,428,237.9,428z"/>
<path class="st1" d="M237.9,649.8c-21.2,0-38.5-17.2-38.5-38.5s17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
S259.2,649.8,237.9,649.8z M237.9,574.9c-20.1,0-36.5,16.3-36.5,36.5s16.3,36.5,36.5,36.5s36.5-16.3,36.5-36.5l0,0
C274.4,591.2,258.1,574.9,237.9,574.9z"/>
<path class="st1" d="M311.4,576.3c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5s38.5,17.2,38.5,38.5l0,0
C349.8,559.1,332.6,576.3,311.4,576.3z M311.4,501.4c-20.1,0-36.5,16.3-36.5,36.5s16.3,36.5,36.5,36.5c20.1,0,36.5-16.3,36.5-36.5
l0,0C347.8,517.7,331.5,501.4,311.4,501.4L311.4,501.4z"/>
<path class="st1" d="M164.5,576.3c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5s38.5,17.2,38.5,38.5l0,0
C202.9,559.1,185.7,576.3,164.5,576.3z M164.5,501.4c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5l0,0C200.9,517.7,184.6,501.4,164.5,501.4L164.5,501.4z"/>
<path class="st1" d="M314.1,753.7h-45c-5.5,0-9.9-4.4-9.9-9.9v-45c0-5.5,4.4-9.9,9.9-9.9h45c5.5,0,9.9,4.4,9.9,9.9v45
C324,749.3,319.5,753.7,314.1,753.7z M269.1,690.9c-4.4,0-7.9,3.6-7.9,7.9v45c0,4.4,3.6,7.9,7.9,7.9h45c4.4,0,7.9-3.6,7.9-7.9v-45
c0-4.4-3.6-7.9-7.9-7.9H269.1z"/>
<path class="st1" d="M291.6,741.7c-11.3,0-20.4-9.2-20.4-20.4c0-11.3,9.2-20.4,20.4-20.4c11.3,0,20.4,9.2,20.4,20.4l0,0
C312,732.6,302.9,741.7,291.6,741.7z M291.6,702.8c-10.2,0-18.4,8.3-18.4,18.4s8.3,18.4,18.4,18.4c10.2,0,18.4-8.3,18.4-18.4
S301.8,702.9,291.6,702.8z"/>
<path class="st1" d="M174.8,260.2h-12.3c-0.6,0-1-0.4-1-1l0,0c1.7-39.6,33.4-71.3,73-73c0.3,0,0.5,0.1,0.7,0.3s0.3,0.4,0.3,0.7v12.3
c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9C181.2,257.6,178.3,260.2,174.8,260.2z M163.6,258.2h11.2c2.5,0,4.6-1.8,4.9-4.3
c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-11.2C196.2,190.3,165.7,220.8,163.6,258.2L163.6,258.2z"/>
<path class="st1" d="M234.6,338.9L234.6,338.9c-39.6-1.7-71.3-33.4-73-73c0-0.6,0.4-1,1-1l0,0h12.3c3.5,0,6.4,2.6,6.9,6
c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9V338C235.6,338.5,235.1,338.9,234.6,338.9L234.6,338.9z M163.6,266.9
c2.2,37.4,32.6,67.8,70,70v-11.2c0-2.5-1.8-4.6-4.3-4.9c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3H163.6z"/>
<path class="st1" d="M241.3,338.9c-0.6,0-1-0.4-1-1v-12.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6
h12.3c0.6,0,1,0.4,1,1l0,0C312.6,305.5,280.9,337.2,241.3,338.9L241.3,338.9z M301,266.9c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v11.2c37.4-2.2,67.8-32.6,70-70H301z"/>
<path class="st1" d="M313.3,260.2H301c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-12.3
c0-0.3,0.1-0.5,0.3-0.7s0.5-0.3,0.7-0.3c39.6,1.7,71.3,33.4,73,73C314.3,259.7,313.9,260.2,313.3,260.2L313.3,260.2L313.3,260.2z
M242.3,188.2v11.2c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h11.2
C310.1,220.8,279.6,190.3,242.3,188.2L242.3,188.2z"/>
<path class="st1" d="M237.9,339c-1.2,0-2.3,0-3.4-0.1c-0.5,0-0.9-0.5-0.9-1v-12.3c0-2.5-1.8-4.6-4.3-4.9
c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3h-12.3c-0.5,0-1-0.4-1-0.9c-0.1-1.1-0.1-2.2-0.1-3.4s0-2.3,0.1-3.4
c0-0.5,0.5-0.9,1-0.9h12.3c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-12.3c0-0.5,0.4-1,0.9-1
c2.3-0.1,4.5-0.1,6.8,0c0.5,0,0.9,0.5,0.9,1v12.3c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h12.3
c0.5,0,1,0.4,1,0.9c0.1,1.1,0.1,2.2,0.1,3.4s0,2.3-0.1,3.4c0,0.5-0.5,0.9-1,0.9H301c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v12.3c0,0.5-0.4,1-0.9,1C240.2,339,239.1,339,237.9,339z M235.6,337
c1.5,0.1,3.1,0.1,4.7,0v-11.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6h11.3c0-0.8,0-1.5,0-2.3
s0-1.6,0-2.3H301c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-11.3c-1.5-0.1-3.1-0.1-4.7,0v11.3
c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9c-0.5,3.4-3.4,6-6.9,6h-11.3c0,0.8,0,1.5,0,2.3s0,1.6,0,2.3h11.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9L235.6,337z"/>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000.8 1000" style="enable-background:new 0 0 1000.8 1000;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.1;}
.st1{fill:#02C5E5;}
.st2{fill:#FF5F55;}
.st3{fill:#FFFFFF;}
</style>
<g class="st0">
<path class="st1" d="M419.1,642.6v67.6c0,3.3-2.7,6-6,6h-4.2v-79.5h4.2C416.4,636.6,419.1,639.3,419.1,642.6z"/>
<path class="st1" d="M419.1,239.8v67.6c0,3.3-2.7,6-6,6h-4.2v-79.5h4.2C416.4,233.9,419.1,236.5,419.1,239.8z"/>
<path class="st1" d="M330.1,7v2.6h-54.2c-84.8,0-161.4,50.7-194.6,128.7l-3.4-3.4c-1.8-1.7-2.3-4.4-1.3-6.6
C111.2,50.8,188.1,1,272.9,1h51.2C327.4,1,330.1,3.7,330.1,7z"/>
<path class="st1" d="M359.6,115.1h-46.9c-1.6,0-3-1.3-3-3v-11.7c0-1.6,1.3-3,3-3h46.9c1.6,0,3,1.3,3,3v11.7
C362.6,113.8,361.3,115.1,359.6,115.1z"/>
<circle class="st1" cx="237.9" cy="464.4" r="37.5"/>
<circle class="st1" cx="237.9" cy="611.3" r="37.5"/>
<circle class="st1" cx="311.4" cy="537.9" r="37.5"/>
<ellipse transform="matrix(0.9951 -9.853756e-02 9.853756e-02 0.9951 -52.201 18.8252)" class="st1" cx="164.5" cy="537.9" rx="37.5" ry="37.5"/>
<path class="st1" d="M269.1,689.9h45c4.9,0,8.9,4,8.9,8.9v45c0,4.9-4,8.9-8.9,8.9h-45c-4.9,0-8.9-4-8.9-8.9v-45
C260.2,693.9,264.2,689.9,269.1,689.9z"/>
<circle class="st1" cx="291.6" cy="721.3" r="19.4"/>
<path class="st1" d="M234.6,187.1v12.3c0,3-2.2,5.5-5.2,5.9c-25.2,3.7-45,23.5-48.7,48.7c-0.4,2.9-2.9,5.1-5.9,5.2h-12.3
C164.3,220.1,195.5,188.9,234.6,187.1z"/>
<path class="st1" d="M234.6,325.6v12.3c-39.1-1.7-70.3-33-72.1-72h12.3c3,0,5.5,2.2,5.9,5.2c3.7,25.2,23.5,45,48.7,48.7
C232.4,320.1,234.6,322.6,234.6,325.6z"/>
<path class="st1" d="M313.3,265.9c-1.7,39.1-33,70.3-72.1,72v-12.3c0-3,2.2-5.5,5.2-5.9c25.2-3.7,45-23.5,48.7-48.7
c0.4-2.9,2.9-5.1,5.9-5.2L313.3,265.9z"/>
<path class="st1" d="M313.3,259.2H301c-3,0-5.5-2.2-5.9-5.2c-3.7-25.2-23.5-45-48.7-48.7c-2.9-0.4-5.1-2.9-5.2-5.9v-12.3
C280.3,188.9,311.6,220.1,313.3,259.2z"/>
<path class="st1" d="M313.4,262.5c0,1.1,0,2.2-0.1,3.3H301c-3,0-5.5,2.2-5.9,5.2c-3.7,25.2-23.5,45-48.7,48.7
c-2.9,0.4-5.1,2.9-5.2,5.9v12.3c-1.1,0.1-2.2,0.1-3.3,0.1s-2.2,0-3.3-0.1v-12.3c0-3-2.2-5.5-5.2-5.9c-25.2-3.7-45-23.5-48.7-48.7
c-0.4-2.9-2.9-5.1-5.9-5.2h-12.3c-0.1-1.1-0.1-2.2-0.1-3.3s0-2.2,0.1-3.3h12.3c3,0,5.5-2.2,5.9-5.2c3.7-25.2,23.5-45,48.7-48.7
c2.9-0.4,5.1-2.9,5.2-5.9v-12.3c1.1-0.1,2.2-0.1,3.3-0.1s2.2,0,3.3,0.1v12.3c0,3,2.2,5.5,5.2,5.9c25.2,3.7,45,23.5,48.7,48.7
c0.4,2.9,2.9,5.1,5.9,5.2h12.3C313.4,260.3,313.4,261.4,313.4,262.5z"/>
</g>
<g class="st0">
<path class="st2" d="M597.9,233.9v79.5h-4.2c-3.3,0-6-2.7-6-6v-67.6c0-3.3,2.7-6,6-6H597.9z"/>
<path class="st2" d="M597.9,636.6v79.5h-4.2c-3.3,0-6-2.7-6-6v-67.6c0-3.3,2.7-6,6-6H597.9z"/>
<path class="st2" d="M929,134.9l-3.4,3.4C892.4,60.3,815.8,9.6,730.9,9.6h-54.2V7c0-3.3,2.7-6,6-6c0,0,0,0,0,0h51.2
c84.8,0,161.7,49.8,196.4,127.2C931.3,130.5,930.8,133.1,929,134.9z"/>
<path class="st2" d="M679.5,94.5V82.8c0-1.6-1.3-3-3-3l0,0h-11.7c-1.6,0-3,1.3-3,3c0,0,0,0,0,0v11.7c0,1.6-1.3,3-3,3l0,0h-11.7
c-1.6,0-3,1.3-3,3c0,0,0,0,0,0v11.7c0,1.6,1.3,3,3,3l0,0h11.7c1.6,0,3,1.3,3,3c0,0,0,0,0,0v11.7c0,1.6,1.3,3,3,3l0,0h11.7
c1.6,0,3-1.3,3-3v0v-11.7c0-1.6,1.3-3,3-3l0,0h11.7c1.6,0,3-1.3,3-3c0,0,0,0,0,0v-11.7c0-1.6-1.3-3-3-3l0,0h-11.7
C680.8,97.5,679.5,96.1,679.5,94.5C679.5,94.5,679.5,94.5,679.5,94.5z"/>
<circle class="st2" cx="768.9" cy="333.9" r="37.5"/>
<circle class="st2" cx="768.9" cy="187.1" r="37.5"/>
<circle class="st2" cx="842.3" cy="260.5" r="37.5"/>
<circle class="st2" cx="695.5" cy="260.5" r="37.5"/>
<circle class="st2" cx="715" cy="721.3" r="27.9"/>
<path class="st2" d="M765.6,460.3v12.3c0,3-2.2,5.5-5.2,5.9c-25.2,3.7-45,23.5-48.7,48.7c-0.4,2.9-2.9,5.1-5.9,5.2h-12.3
C695.2,493.3,726.5,462,765.6,460.3z"/>
<path class="st2" d="M765.6,598.8v12.3c-39.1-1.7-70.3-33-72.1-72h12.3c3,0,5.5,2.2,5.9,5.2c3.7,25.2,23.5,45,48.7,48.7
C763.4,593.3,765.6,595.8,765.6,598.8z"/>
<path class="st2" d="M844.3,539c-1.7,39.1-33,70.3-72.1,72v-12.3c0-3,2.2-5.5,5.2-5.9c25.2-3.7,45-23.5,48.7-48.7
c0.4-2.9,2.9-5.1,5.9-5.2L844.3,539z"/>
<path class="st2" d="M844.3,532.4H832c-3,0-5.5-2.2-5.9-5.2c-3.7-25.2-23.5-45-48.7-48.7c-2.9-0.4-5.1-2.9-5.2-5.9v-12.3
C811.3,462,842.6,493.3,844.3,532.4z"/>
<path class="st2" d="M844.4,535.7c0,1.1,0,2.2-0.1,3.3H832c-3,0-5.5,2.2-5.9,5.2c-3.7,25.2-23.5,45-48.7,48.7
c-2.9,0.4-5.1,2.9-5.2,5.9v12.3c-1.1,0.1-2.2,0.1-3.3,0.1s-2.2,0-3.3-0.1v-12.3c0-3-2.2-5.5-5.2-5.9c-25.2-3.7-45-23.5-48.7-48.7
c-0.4-2.9-2.9-5.1-5.9-5.2h-12.3c-0.1-1.1-0.1-2.2-0.1-3.3s0-2.2,0.1-3.3h12.3c3,0,5.5-2.2,5.9-5.2c3.7-25.2,23.5-45,48.7-48.7
c2.9-0.4,5.1-2.9,5.2-5.9v-12.3c1.1-0.1,2.2-0.1,3.3-0.1s2.2,0,3.3,0.1v12.3c0,3,2.2,5.5,5.2,5.9c25.2,3.7,45,23.5,48.7,48.7
c0.4,2.9,2.9,5.1,5.9,5.2h12.3C844.3,533.5,844.4,534.6,844.4,535.7z"/>
</g>
<path class="st3" d="M413.1,906.6h-7.9c-3.6,0-6.4-2.9-6.5-6.5V71.2c0-3.6,2.9-6.4,6.5-6.5h7.9c3.6,0,6.4,2.9,6.5,6.5V207
c0,4.9-1.2,9.6-3.4,14l-6.7,13v79.2l6.7,13c2.2,4.3,3.4,9.1,3.4,13.9v269.7c0,4.9-1.2,9.6-3.4,14l-6.7,13V716l6.7,13
c2.2,4.3,3.4,9.1,3.4,13.9v157.2C419.6,903.7,416.7,906.6,413.1,906.6z M405.2,65.7c-3,0-5.5,2.4-5.5,5.5v828.9c0,3,2.4,5.5,5.5,5.5
h7.9c3,0,5.5-2.4,5.5-5.5V742.9c0-4.7-1.1-9.3-3.3-13.5l-6.8-13.1c0-0.1-0.1-0.2-0.1-0.2v-79.5c0-0.1,0-0.2,0.1-0.2l6.8-13.1
c2.2-4.2,3.3-8.8,3.3-13.5V340.1c0-4.7-1.1-9.3-3.3-13.5l-6.8-13.1c0-0.1-0.1-0.2-0.1-0.2v-79.5c0-0.1,0-0.2,0.1-0.2l6.8-13.1
c2.2-4.2,3.3-8.8,3.3-13.5V71.2c0-3-2.4-5.5-5.5-5.5L405.2,65.7z"/>
<path class="st3" d="M399.3,858.9h-11.2c-0.3,0-0.5-0.2-0.5-0.5V72c0-0.3,0.2-0.5,0.5-0.5h11.2c0.3,0,0.5,0.2,0.5,0.5v786.4
C399.8,858.7,399.6,858.9,399.3,858.9z M388.6,857.9h10.2V72.5h-10.2V857.9z"/>
<path class="st3" d="M382.1,1000H275.9C158.9,1000,64,905.2,64,788.1c0,0,0,0,0,0V220.9C64,104.1,159.1,9.1,275.9,9.1h106.2
c3.6,0,6.5,2.9,6.5,6.5v978C388.6,997.1,385.7,1000,382.1,1000z M275.9,10.1C159.6,10.1,65,104.7,65,220.9v567.2
C65,904.4,159.6,999,275.9,999h106.2c3,0,5.5-2.4,5.5-5.5v-978c0-3-2.4-5.5-5.5-5.5H275.9z"/>
<path class="st3" d="M601.6,906.6h-7.9c-3.6,0-6.4-2.9-6.5-6.5V742.9c0-4.9,1.2-9.6,3.4-13.9l6.7-13v-79.2l-6.7-13
c-2.2-4.3-3.4-9.1-3.4-14V340.1c0-4.9,1.2-9.6,3.4-13.9l6.7-13V234l-6.7-13c-2.2-4.3-3.4-9.1-3.4-14V71.2c0-3.6,2.9-6.4,6.5-6.5h7.9
c3.6,0,6.4,2.9,6.5,6.5v828.9C608,903.7,605.1,906.6,601.6,906.6z M593.7,65.7c-3,0-5.5,2.4-5.5,5.5V207c0,4.7,1.1,9.3,3.3,13.5
l6.8,13.1c0,0.1,0.1,0.1,0.1,0.2v79.5c0,0.1,0,0.2-0.1,0.2l-6.8,13.1c-2.2,4.2-3.3,8.8-3.3,13.5v269.7c0,4.7,1.1,9.3,3.3,13.5
l6.8,13.1c0,0.1,0.1,0.1,0.1,0.2v79.5c0,0.1,0,0.2-0.1,0.2l-6.8,13.1c-2.2,4.2-3.3,8.8-3.3,13.5v157.2c0,3,2.4,5.5,5.5,5.5h7.9
c3,0,5.5-2.4,5.5-5.5V71.2c0-3-2.4-5.5-5.5-5.5L593.7,65.7z"/>
<path class="st3" d="M618.8,858.9h-11.3c-0.3,0-0.5-0.2-0.5-0.5c0,0,0,0,0,0V72c0-0.3,0.2-0.5,0.5-0.5h11.3c0.3,0,0.5,0.2,0.5,0.5
v786.4C619.3,858.7,619.1,858.9,618.8,858.9C618.8,858.9,618.8,858.9,618.8,858.9z M608,857.9h10.3V72.5H608V857.9z"/>
<path class="st3" d="M730.9,1000H624.7c-3.6,0-6.5-2.9-6.5-6.5v-978c0-3.6,2.9-6.5,6.5-6.5h106.2c116.8,0,211.9,95.1,211.9,211.9
v567.2C942.8,905.1,848,1000,730.9,1000C730.9,1000,730.9,1000,730.9,1000z M624.7,10.1c-3,0-5.5,2.4-5.5,5.5v978
c0,3,2.4,5.5,5.5,5.5h106.2c116.3,0,210.9-94.6,210.9-210.9V220.9c0-116.3-94.6-210.9-210.9-210.9L624.7,10.1z"/>
<path class="st3" d="M715,763.2c-23.1,0-41.9-18.7-41.9-41.9s18.7-41.9,41.9-41.9s41.9,18.7,41.9,41.9l0,0
C756.8,744.4,738.1,763.1,715,763.2z M715,680.4c-22.6,0-40.9,18.3-40.9,40.9c0,22.6,18.3,40.9,40.9,40.9
c22.6,0,40.9-18.3,40.9-40.9v0C755.8,698.7,737.6,680.4,715,680.4z"/>
<polygon class="st1" points="237.9,448.9 225.8,469.9 250,469.9 "/>
<polygon class="st1" points="237.9,626.9 225.8,605.9 250,605.9 "/>
<polygon class="st1" points="148.9,537.9 169.9,550 169.9,525.8 "/>
<polygon class="st1" points="326.9,537.9 305.9,550 305.9,525.8 "/>
<path class="st2" d="M782.2,203.2h-5.5l-7.8-12.9l-7.8,12.9h-5.4l10.6-16.3l-9.8-15.6h5.2l7.3,12l7.4-12h5l-9.8,15.4L782.2,203.2z"
/>
<path class="st2" d="M709.2,244.5l-11.6,20.6v11.4h-4.4V265l-11.6-20.5h5.3l6.4,11.7l2.3,4.7l2.2-4.3l6.4-12.1L709.2,244.5z"/>
<path class="st2" d="M855.9,276.5h-4.7l-2.2-7h-13.3l-2.3,7h-4.5l10.6-32h6L855.9,276.5z M847.7,265.6l-5.4-17.1l-5.4,17.1
L847.7,265.6z"/>
<path class="st2" d="M779.4,340.4c0,1.4-0.3,2.8-0.9,4.1c-0.6,1.2-1.5,2.2-2.5,3c-1.2,0.9-2.6,1.5-4,1.9c-1.7,0.4-3.4,0.7-5.2,0.6
h-8.4v-32h9.2c7.1,0,10.7,2.6,10.7,7.8c0,1.6-0.4,3.1-1.2,4.5c-1,1.4-2.4,2.3-4,2.8c0.9,0.2,1.7,0.4,2.5,0.8c0.8,0.4,1.5,0.9,2,1.5
c0.6,0.6,1.1,1.4,1.4,2.2C779.2,338.4,779.4,339.4,779.4,340.4z M773.7,326.3c0-0.6-0.1-1.3-0.3-1.8c-0.2-0.6-0.6-1.1-1-1.5
c-0.6-0.5-1.3-0.8-2-1c-1-0.3-2.1-0.4-3.2-0.4h-4.5v10h4.4c0.9,0,1.8-0.1,2.7-0.3c0.8-0.2,1.5-0.5,2.1-1c0.6-0.4,1-1,1.3-1.7
C773.6,327.9,773.7,327.1,773.7,326.3L773.7,326.3z M774.8,340.5c0-0.8-0.2-1.5-0.5-2.2c-0.4-0.7-0.9-1.2-1.5-1.7
c-0.7-0.5-1.5-0.8-2.4-1c-1-0.3-2.1-0.4-3.2-0.4h-4.5v11h4.6c2.5,0,4.4-0.5,5.6-1.4C774.2,343.8,774.9,342.2,774.8,340.5
L774.8,340.5z"/>
<path class="st2" d="M715,701.3L695.4,721h5.6v16.8h28.2V721h5.3L715,701.3z M720.7,731.8h-11.1V721h11.1V731.8z"/>
<path class="st1" d="M413.1,717.1h-4.2c-0.6,0-1-0.4-1-1c0,0,0,0,0,0v-79.5c0-0.6,0.4-1,1-1c0,0,0,0,0,0h4.2c3.8,0,6.9,3.1,7,7v67.6
C420.1,714,417,717.1,413.1,717.1z M409.9,715.1h3.2c2.7,0,5-2.2,5-5v-67.6c0-2.7-2.2-5-5-5h-3.2V715.1z"/>
<path class="st1" d="M413.1,314.3h-4.2c-0.6,0-1-0.4-1-1v-79.5c0-0.6,0.4-1,1-1h4.2c3.8,0,6.9,3.1,7,7v67.6
C420.1,311.2,417,314.3,413.1,314.3z M409.9,312.3h3.2c2.7,0,5-2.2,5-5v-67.6c0-2.7-2.2-5-5-5h-3.2V312.3z"/>
<path class="st1" d="M81.3,139.3c-0.3,0-0.5-0.1-0.7-0.3l-3.4-3.4c-2-2-2.6-5.1-1.5-7.8C110.5,50.1,187.7,0.1,272.9,0h51.2
c3.8,0,6.9,3.1,7,7v2.6c0,0.6-0.4,1-1,1h-54.2C191.4,10.5,115.1,61,82.2,138.7c-0.1,0.3-0.4,0.5-0.7,0.6
C81.4,139.3,81.3,139.3,81.3,139.3z M272.9,2C188.5,2.1,112,51.7,77.5,128.7c-0.8,1.9-0.4,4.1,1.1,5.5l2.4,2.4
c33.6-77.8,110.3-128.1,195-128h53.2V7c0-2.7-2.2-5-5-5L272.9,2z"/>
<path class="st1" d="M359.6,116.1h-46.9c-2.2,0-4-1.8-4-4v-11.7c0-2.2,1.8-4,4-4h46.9c2.2,0,4,1.8,4,4v11.7
C363.6,114.3,361.8,116.1,359.6,116.1z M312.7,98.5c-1.1,0-2,0.9-2,2v11.7c0,1.1,0.9,2,2,2h46.9c1.1,0,2-0.9,2-2v-11.7
c0-1.1-0.9-2-2-2H312.7z"/>
<path class="st1" d="M237.9,502.9c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C276.4,485.7,259.2,502.9,237.9,502.9z M237.9,428c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C274.4,444.3,258.1,428,237.9,428z"/>
<path class="st1" d="M237.9,649.8c-21.2,0-38.5-17.2-38.5-38.5s17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C276.4,632.6,259.2,649.8,237.9,649.8z M237.9,574.9c-20.1,0-36.5,16.3-36.5,36.5s16.3,36.5,36.5,36.5s36.5-16.3,36.5-36.5
c0,0,0,0,0,0C274.4,591.2,258.1,574.9,237.9,574.9z"/>
<path class="st1" d="M311.4,576.3c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5s38.5,17.2,38.5,38.5l0,0
C349.8,559.1,332.6,576.3,311.4,576.3z M311.4,501.4c-20.1,0-36.5,16.3-36.5,36.5s16.3,36.5,36.5,36.5c20.1,0,36.5-16.3,36.5-36.5
c0,0,0,0,0,0C347.8,517.7,331.5,501.4,311.4,501.4L311.4,501.4z"/>
<path class="st1" d="M164.5,576.3c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5s38.5,17.2,38.5,38.5l0,0
C202.9,559.1,185.7,576.3,164.5,576.3z M164.5,501.4c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5c0,0,0,0,0,0C200.9,517.7,184.6,501.4,164.5,501.4L164.5,501.4z"/>
<path class="st1" d="M314.1,753.7h-45c-5.5,0-9.9-4.4-9.9-9.9v-45c0-5.5,4.4-9.9,9.9-9.9h45c5.5,0,9.9,4.4,9.9,9.9v45
C324,749.3,319.5,753.7,314.1,753.7z M269.1,690.9c-4.4,0-7.9,3.6-7.9,7.9v45c0,4.4,3.6,7.9,7.9,7.9h45c4.4,0,7.9-3.6,7.9-7.9v-45
c0-4.4-3.6-7.9-7.9-7.9H269.1z"/>
<path class="st1" d="M291.6,741.7c-11.3,0-20.4-9.2-20.4-20.4c0-11.3,9.2-20.4,20.4-20.4c11.3,0,20.4,9.2,20.4,20.4c0,0,0,0,0,0
C312,732.6,302.9,741.7,291.6,741.7z M291.6,702.8c-10.2,0-18.4,8.3-18.4,18.4s8.3,18.4,18.4,18.4c10.2,0,18.4-8.3,18.4-18.4
C310,711.1,301.8,702.9,291.6,702.8z"/>
<path class="st1" d="M174.8,260.2h-12.3c-0.6,0-1-0.4-1-1c0,0,0,0,0,0c1.7-39.6,33.4-71.3,73-73c0.3,0,0.5,0.1,0.7,0.3
c0.2,0.2,0.3,0.4,0.3,0.7v12.3c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9C181.2,257.6,178.3,260.2,174.8,260.2z
M163.6,258.2h11.2c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-11.2
C196.2,190.3,165.7,220.8,163.6,258.2L163.6,258.2z"/>
<path class="st1" d="M234.6,338.9L234.6,338.9c-39.6-1.7-71.3-33.4-73-73c0-0.6,0.4-1,1-1c0,0,0,0,0,0h12.3c3.5,0,6.4,2.6,6.9,6
c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9v12.3C235.6,338.5,235.1,338.9,234.6,338.9L234.6,338.9z M163.6,266.9
c2.2,37.4,32.6,67.8,70,70v-11.2c0-2.5-1.8-4.6-4.3-4.9c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3L163.6,266.9z"/>
<path class="st1" d="M241.3,338.9c-0.6,0-1-0.4-1-1v-12.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6
h12.3c0.6,0,1,0.4,1,1c0,0,0,0,0,0C312.6,305.5,280.9,337.2,241.3,338.9L241.3,338.9z M301,266.9c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v11.2c37.4-2.2,67.8-32.6,70-70L301,266.9z"/>
<path class="st1" d="M313.3,260.2H301c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-12.3
c0-0.3,0.1-0.5,0.3-0.7c0.2-0.2,0.5-0.3,0.7-0.3c39.6,1.7,71.3,33.4,73,73C314.3,259.7,313.9,260.2,313.3,260.2
C313.3,260.2,313.3,260.2,313.3,260.2L313.3,260.2z M242.3,188.2v11.2c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6
c0.3,2.5,2.4,4.3,4.9,4.3h11.2C310.1,220.8,279.6,190.3,242.3,188.2L242.3,188.2z"/>
<path class="st1" d="M237.9,339c-1.2,0-2.3,0-3.4-0.1c-0.5,0-0.9-0.5-0.9-1v-12.3c0-2.5-1.8-4.6-4.3-4.9
c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3h-12.3c-0.5,0-1-0.4-1-0.9c-0.1-1.1-0.1-2.2-0.1-3.4s0-2.3,0.1-3.4
c0-0.5,0.5-0.9,1-0.9h12.3c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-12.3c0-0.5,0.4-1,0.9-1
c2.3-0.1,4.5-0.1,6.8,0c0.5,0,0.9,0.5,0.9,1v12.3c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h12.3
c0.5,0,1,0.4,1,0.9c0.1,1.1,0.1,2.2,0.1,3.4s0,2.3-0.1,3.4c0,0.5-0.5,0.9-1,0.9H301c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v12.3c0,0.5-0.4,1-0.9,1C240.2,339,239.1,339,237.9,339z M235.6,337
c1.5,0.1,3.1,0.1,4.7,0v-11.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6h11.3c0-0.8,0-1.5,0-2.3
s0-1.6,0-2.3H301c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-11.3c-1.5-0.1-3.1-0.1-4.7,0v11.3
c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9c-0.5,3.4-3.4,6-6.9,6h-11.3c0,0.8,0,1.5,0,2.3s0,1.6,0,2.3h11.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9L235.6,337z"/>
<path class="st2" d="M597.9,314.3h-4.2c-3.8,0-6.9-3.1-7-7v-67.6c0-3.8,3.1-6.9,7-7h4.2c0.6,0,1,0.4,1,1c0,0,0,0,0,0v79.5
C598.9,313.9,598.4,314.3,597.9,314.3C597.9,314.3,597.9,314.3,597.9,314.3z M593.7,234.8c-2.7,0-5,2.2-5,5v67.6c0,2.7,2.2,5,5,5
h3.2v-77.5H593.7z"/>
<path class="st2" d="M597.9,717.1h-4.2c-3.8,0-6.9-3.1-7-7v-67.6c0-3.8,3.1-6.9,7-7h4.2c0.6,0,1,0.4,1,1c0,0,0,0,0,0v79.5
C598.9,716.6,598.4,717.1,597.9,717.1C597.9,717.1,597.9,717.1,597.9,717.1z M593.7,637.6c-2.7,0-5,2.2-5,5v67.6c0,2.7,2.2,5,5,5
h3.2v-77.5H593.7z"/>
<path class="st2" d="M925.6,139.3c-0.1,0-0.1,0-0.2,0c-0.3-0.1-0.6-0.3-0.7-0.6C891.7,61,815.4,10.5,730.9,10.6h-54.2
c-0.6,0-1-0.4-1-1c0,0,0,0,0,0V7c0-3.8,3.1-6.9,7-7h51.2c85.2,0.1,162.4,50.1,197.3,127.8c1.2,2.6,0.6,5.7-1.5,7.8l-3.4,3.4
C926.1,139.2,925.8,139.3,925.6,139.3z M677.7,8.6h53.2c84.7-0.1,161.3,50.2,195,128l2.4-2.4l0,0c1.5-1.4,1.9-3.6,1.1-5.5
C894.8,51.7,818.3,2.1,733.9,2h-51.2c-2.7,0-5,2.2-5,5V8.6z"/>
<path class="st2" d="M676.5,133.7h-11.7c-2.2,0-4-1.8-4-4v-11.7c0-1.1-0.9-2-2-2h-11.7c-2.2,0-4-1.8-4-4v-11.7c0-2.2,1.8-4,4-4h11.7
c1.1,0,2-0.9,2-2V82.8c0-2.2,1.8-4,4-4h11.7c2.2,0,4,1.8,4,4v11.7c0,1.1,0.9,2,2,2h11.7c2.2,0,4,1.8,4,4v11.7c0,2.2-1.8,4-4,4h-11.7
c-1.1,0-2,0.9-2,2v11.7C680.5,131.9,678.7,133.7,676.5,133.7z M647.2,98.5c-1.1,0-2,0.9-2,2v11.7c0,1.1,0.9,2,2,2h11.7
c2.2,0,4,1.8,4,4v11.7c0,1.1,0.9,2,2,2h11.7c1.1,0,2-0.9,2-2v-11.7c0-2.2,1.8-4,4-4h11.7c1.1,0,2-0.9,2-2v-11.7c0-1.1-0.9-2-2-2
h-11.7c-2.2,0-4-1.8-4-4V82.8c0-1.1-0.9-2-2-2h-11.7c-1.1,0-2,0.9-2,2v11.7c0,2.2-1.8,4-4,4L647.2,98.5z"/>
<path class="st2" d="M768.9,372.4c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C807.3,355.2,790.1,372.4,768.9,372.4z M768.9,297.5c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C805.3,313.8,789,297.5,768.9,297.5L768.9,297.5z"/>
<path class="st2" d="M768.9,225.5c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C807.3,208.3,790.1,225.5,768.9,225.5z M768.9,150.6c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C805.3,166.9,789,150.6,768.9,150.6L768.9,150.6z"/>
<path class="st2" d="M842.3,299c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C880.8,281.7,863.6,298.9,842.3,299z M842.3,224c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C878.8,240.4,862.5,224,842.3,224L842.3,224z"/>
<path class="st2" d="M695.5,299c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C733.9,281.7,716.7,298.9,695.5,299z M695.5,224c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C731.9,240.4,715.6,224,695.5,224L695.5,224z"/>
<path class="st2" d="M715,750.2c-16,0-28.9-13-28.9-28.9s13-28.9,28.9-28.9c16,0,28.9,13,28.9,28.9c0,0,0,0,0,0
C743.9,737.3,731,750.2,715,750.2z M715,694.3c-14.9,0-26.9,12.1-26.9,26.9s12.1,26.9,26.9,26.9c14.9,0,26.9-12.1,26.9-26.9
C741.9,706.4,729.9,694.4,715,694.3z"/>
<path class="st2" d="M705.8,533.4h-12.3c-0.6,0-1-0.4-1-1c0,0,0,0,0,0c1.7-39.6,33.4-71.3,73-73c0.3,0,0.5,0.1,0.7,0.3
c0.2,0.2,0.3,0.4,0.3,0.7v12.3c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9C712.2,530.8,709.3,533.4,705.8,533.4z
M694.6,531.4h11.2c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-11.2
C727.2,463.5,696.7,494,694.6,531.4z"/>
<path class="st2" d="M765.6,612.1C765.6,612.1,765.5,612.1,765.6,612.1c-39.6-1.7-71.3-33.4-73-73c0-0.6,0.4-1,1-1c0,0,0,0,0,0h12.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9v12.3C766.6,611.6,766.1,612.1,765.6,612.1
C765.6,612.1,765.6,612.1,765.6,612.1L765.6,612.1z M694.6,540c2.2,37.4,32.6,67.8,70,70v-11.2c0-2.5-1.8-4.6-4.3-4.9
c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3H694.6z"/>
<path class="st2" d="M772.2,612.1c-0.6,0-1-0.4-1-1c0,0,0,0,0,0v-12.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9
c0.5-3.4,3.4-6,6.9-6h12.3c0.6,0,1,0.4,1,1c0,0,0,0,0,0C843.5,578.7,811.9,610.3,772.2,612.1C772.3,612.1,772.3,612.1,772.2,612.1z
M832,540c-2.5,0-4.6,1.8-4.9,4.3c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9V610c37.4-2.2,67.8-32.6,70-70H832z"/>
<path class="st2" d="M844.3,533.4H832c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-12.3
c0-0.3,0.1-0.5,0.3-0.7c0.2-0.2,0.5-0.3,0.7-0.3c39.6,1.7,71.3,33.4,73,73C845.3,532.9,844.9,533.3,844.3,533.4
C844.3,533.4,844.3,533.4,844.3,533.4L844.3,533.4z M773.2,461.4v11.2c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6
c0.3,2.5,2.4,4.3,4.9,4.3h11.2C841.1,494,810.6,463.5,773.2,461.4z"/>
<path class="st2" d="M768.9,612.2c-1.2,0-2.3,0-3.4-0.1c-0.5,0-0.9-0.5-0.9-1v-12.3c0-2.5-1.8-4.6-4.3-4.9
c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3h-12.3c-0.5,0-1-0.4-1-0.9c-0.1-1.1-0.1-2.2-0.1-3.4s0-2.3,0.1-3.4
c0-0.5,0.5-0.9,1-0.9h12.3c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-12.3c0-0.5,0.4-1,0.9-1
c2.3-0.1,4.5-0.1,6.8,0c0.5,0,0.9,0.5,0.9,1v12.3c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h12.3
c0.5,0,1,0.4,1,0.9c0.1,1.1,0.1,2.2,0.1,3.4s0,2.3-0.1,3.4c0,0.5-0.5,0.9-1,0.9H832c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v12.3c0,0.5-0.4,1-0.9,1C771.2,612.1,770.1,612.2,768.9,612.2z M766.6,610.1
c1.5,0.1,3.1,0.1,4.7,0v-11.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6h11.3c0-0.8,0-1.5,0-2.3
s0-1.6,0-2.3H832c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-11.3c-1.5-0.1-3.1-0.1-4.7,0v11.3
c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9c-0.5,3.4-3.4,6-6.9,6h-11.3c0,0.8,0,1.5,0,2.3s0,1.6,0,2.3h11.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9V610.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000.8 1000" style="enable-background:new 0 0 1000.8 1000;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.1;}
.st1{fill:#FF5F55;}
.st2{fill:#FFFFFF;}
</style>
<g class="st0">
<path class="st1" d="M597.9,233.9v79.5h-4.2c-3.3,0-6-2.7-6-6v-67.6c0-3.3,2.7-6,6-6h4.2V233.9z"/>
<path class="st1" d="M597.9,636.6v79.5h-4.2c-3.3,0-6-2.7-6-6v-67.6c0-3.3,2.7-6,6-6L597.9,636.6L597.9,636.6z"/>
<path class="st1" d="M929,134.9l-3.4,3.4C892.4,60.3,815.8,9.6,730.9,9.6h-54.2V7c0-3.3,2.7-6,6-6l0,0h51.2
c84.8,0,161.7,49.8,196.4,127.2C931.3,130.5,930.8,133.1,929,134.9z"/>
<path class="st1" d="M679.5,94.5V82.8c0-1.6-1.3-3-3-3l0,0h-11.7c-1.6,0-3,1.3-3,3l0,0v11.7c0,1.6-1.3,3-3,3l0,0h-11.7
c-1.6,0-3,1.3-3,3l0,0v11.7c0,1.6,1.3,3,3,3l0,0h11.7c1.6,0,3,1.3,3,3l0,0v11.7c0,1.6,1.3,3,3,3l0,0h11.7c1.6,0,3-1.3,3-3l0,0
v-11.7c0-1.6,1.3-3,3-3l0,0h11.7c1.6,0,3-1.3,3-3l0,0v-11.7c0-1.6-1.3-3-3-3l0,0h-11.7C680.8,97.5,679.5,96.1,679.5,94.5
L679.5,94.5z"/>
<circle class="st1" cx="768.9" cy="333.9" r="37.5"/>
<circle class="st1" cx="768.9" cy="187.1" r="37.5"/>
<circle class="st1" cx="842.3" cy="260.5" r="37.5"/>
<circle class="st1" cx="695.5" cy="260.5" r="37.5"/>
<circle class="st1" cx="715" cy="721.3" r="27.9"/>
<path class="st1" d="M765.6,460.3v12.3c0,3-2.2,5.5-5.2,5.9c-25.2,3.7-45,23.5-48.7,48.7c-0.4,2.9-2.9,5.1-5.9,5.2h-12.3
C695.2,493.3,726.5,462,765.6,460.3z"/>
<path class="st1" d="M765.6,598.8v12.3c-39.1-1.7-70.3-33-72.1-72h12.3c3,0,5.5,2.2,5.9,5.2c3.7,25.2,23.5,45,48.7,48.7
C763.4,593.3,765.6,595.8,765.6,598.8z"/>
<path class="st1" d="M844.3,539c-1.7,39.1-33,70.3-72.1,72v-12.3c0-3,2.2-5.5,5.2-5.9c25.2-3.7,45-23.5,48.7-48.7
c0.4-2.9,2.9-5.1,5.9-5.2L844.3,539z"/>
<path class="st1" d="M844.3,532.4H832c-3,0-5.5-2.2-5.9-5.2c-3.7-25.2-23.5-45-48.7-48.7c-2.9-0.4-5.1-2.9-5.2-5.9v-12.3
C811.3,462,842.6,493.3,844.3,532.4z"/>
<path class="st1" d="M844.4,535.7c0,1.1,0,2.2-0.1,3.3H832c-3,0-5.5,2.2-5.9,5.2c-3.7,25.2-23.5,45-48.7,48.7
c-2.9,0.4-5.1,2.9-5.2,5.9v12.3c-1.1,0.1-2.2,0.1-3.3,0.1s-2.2,0-3.3-0.1v-12.3c0-3-2.2-5.5-5.2-5.9c-25.2-3.7-45-23.5-48.7-48.7
c-0.4-2.9-2.9-5.1-5.9-5.2h-12.3c-0.1-1.1-0.1-2.2-0.1-3.3s0-2.2,0.1-3.3h12.3c3,0,5.5-2.2,5.9-5.2c3.7-25.2,23.5-45,48.7-48.7
c2.9-0.4,5.1-2.9,5.2-5.9v-12.3c1.1-0.1,2.2-0.1,3.3-0.1s2.2,0,3.3,0.1v12.3c0,3,2.2,5.5,5.2,5.9c25.2,3.7,45,23.5,48.7,48.7
c0.4,2.9,2.9,5.1,5.9,5.2h12.3C844.3,533.5,844.4,534.6,844.4,535.7z"/>
</g>
<path class="st2" d="M601.6,906.6h-7.9c-3.6,0-6.4-2.9-6.5-6.5V742.9c0-4.9,1.2-9.6,3.4-13.9l6.7-13v-79.2l-6.7-13
c-2.2-4.3-3.4-9.1-3.4-14V340.1c0-4.9,1.2-9.6,3.4-13.9l6.7-13V234l-6.7-13c-2.2-4.3-3.4-9.1-3.4-14V71.2c0-3.6,2.9-6.4,6.5-6.5h7.9
c3.6,0,6.4,2.9,6.5,6.5v828.9C608,903.7,605.1,906.6,601.6,906.6z M593.7,65.7c-3,0-5.5,2.4-5.5,5.5V207c0,4.7,1.1,9.3,3.3,13.5
l6.8,13.1c0,0.1,0.1,0.1,0.1,0.2v79.5c0,0.1,0,0.2-0.1,0.2l-6.8,13.1c-2.2,4.2-3.3,8.8-3.3,13.5v269.7c0,4.7,1.1,9.3,3.3,13.5
l6.8,13.1c0,0.1,0.1,0.1,0.1,0.2v79.5c0,0.1,0,0.2-0.1,0.2l-6.8,13.1c-2.2,4.2-3.3,8.8-3.3,13.5v157.2c0,3,2.4,5.5,5.5,5.5h7.9
c3,0,5.5-2.4,5.5-5.5V71.2c0-3-2.4-5.5-5.5-5.5H593.7z"/>
<path class="st2" d="M618.8,858.9h-11.3c-0.3,0-0.5-0.2-0.5-0.5l0,0V72c0-0.3,0.2-0.5,0.5-0.5h11.3c0.3,0,0.5,0.2,0.5,0.5v786.4
C619.3,858.7,619.1,858.9,618.8,858.9L618.8,858.9z M608,857.9h10.3V72.5H608V857.9z"/>
<path class="st2" d="M730.9,1000H624.7c-3.6,0-6.5-2.9-6.5-6.5v-978c0-3.6,2.9-6.5,6.5-6.5h106.2c116.8,0,211.9,95.1,211.9,211.9
v567.2C942.8,905.1,848,1000,730.9,1000L730.9,1000z M624.7,10.1c-3,0-5.5,2.4-5.5,5.5v978c0,3,2.4,5.5,5.5,5.5h106.2
c116.3,0,210.9-94.6,210.9-210.9V220.9C941.8,104.6,847.2,10,730.9,10L624.7,10.1z"/>
<path class="st2" d="M715,763.2c-23.1,0-41.9-18.7-41.9-41.9s18.7-41.9,41.9-41.9s41.9,18.7,41.9,41.9l0,0
C756.8,744.4,738.1,763.1,715,763.2z M715,680.4c-22.6,0-40.9,18.3-40.9,40.9c0,22.6,18.3,40.9,40.9,40.9
c22.6,0,40.9-18.3,40.9-40.9l0,0C755.8,698.7,737.6,680.4,715,680.4z"/>
<path class="st1" d="M782.2,203.2h-5.5l-7.8-12.9l-7.8,12.9h-5.4l10.6-16.3l-9.8-15.6h5.2l7.3,12l7.4-12h5l-9.8,15.4L782.2,203.2z"
/>
<path class="st1" d="M709.2,244.5l-11.6,20.6v11.4h-4.4V265l-11.6-20.5h5.3l6.4,11.7l2.3,4.7l2.2-4.3l6.4-12.1L709.2,244.5z"/>
<path class="st1" d="M855.9,276.5h-4.7l-2.2-7h-13.3l-2.3,7h-4.5l10.6-32h6L855.9,276.5z M847.7,265.6l-5.4-17.1l-5.4,17.1H847.7z"
/>
<path class="st1" d="M779.4,340.4c0,1.4-0.3,2.8-0.9,4.1c-0.6,1.2-1.5,2.2-2.5,3c-1.2,0.9-2.6,1.5-4,1.9c-1.7,0.4-3.4,0.7-5.2,0.6
h-8.4v-32h9.2c7.1,0,10.7,2.6,10.7,7.8c0,1.6-0.4,3.1-1.2,4.5c-1,1.4-2.4,2.3-4,2.8c0.9,0.2,1.7,0.4,2.5,0.8s1.5,0.9,2,1.5
c0.6,0.6,1.1,1.4,1.4,2.2C779.2,338.4,779.4,339.4,779.4,340.4z M773.7,326.3c0-0.6-0.1-1.3-0.3-1.8c-0.2-0.6-0.6-1.1-1-1.5
c-0.6-0.5-1.3-0.8-2-1c-1-0.3-2.1-0.4-3.2-0.4h-4.5v10h4.4c0.9,0,1.8-0.1,2.7-0.3c0.8-0.2,1.5-0.5,2.1-1c0.6-0.4,1-1,1.3-1.7
C773.6,327.9,773.7,327.1,773.7,326.3L773.7,326.3z M774.8,340.5c0-0.8-0.2-1.5-0.5-2.2c-0.4-0.7-0.9-1.2-1.5-1.7
c-0.7-0.5-1.5-0.8-2.4-1c-1-0.3-2.1-0.4-3.2-0.4h-4.5v11h4.6c2.5,0,4.4-0.5,5.6-1.4C774.2,343.8,774.9,342.2,774.8,340.5
L774.8,340.5z"/>
<path class="st1" d="M715,701.3L695.4,721h5.6v16.8h28.2V721h5.3L715,701.3z M720.7,731.8h-11.1V721h11.1V731.8z"/>
<path class="st1" d="M597.9,314.3h-4.2c-3.8,0-6.9-3.1-7-7v-67.6c0-3.8,3.1-6.9,7-7h4.2c0.6,0,1,0.4,1,1l0,0v79.5
C598.9,313.9,598.4,314.3,597.9,314.3L597.9,314.3z M593.7,234.8c-2.7,0-5,2.2-5,5v67.6c0,2.7,2.2,5,5,5h3.2v-77.5L593.7,234.8
L593.7,234.8z"/>
<path class="st1" d="M597.9,717.1h-4.2c-3.8,0-6.9-3.1-7-7v-67.6c0-3.8,3.1-6.9,7-7h4.2c0.6,0,1,0.4,1,1l0,0V716
C598.9,716.6,598.4,717.1,597.9,717.1L597.9,717.1z M593.7,637.6c-2.7,0-5,2.2-5,5v67.6c0,2.7,2.2,5,5,5h3.2v-77.5L593.7,637.6
L593.7,637.6z"/>
<path class="st1" d="M925.6,139.3c-0.1,0-0.1,0-0.2,0c-0.3-0.1-0.6-0.3-0.7-0.6C891.7,61,815.4,10.5,730.9,10.6h-54.2
c-0.6,0-1-0.4-1-1l0,0V7c0-3.8,3.1-6.9,7-7h51.2c85.2,0.1,162.4,50.1,197.3,127.8c1.2,2.6,0.6,5.7-1.5,7.8l-3.4,3.4
C926.1,139.2,925.8,139.3,925.6,139.3z M677.7,8.6h53.2c84.7-0.1,161.3,50.2,195,128l2.4-2.4l0,0c1.5-1.4,1.9-3.6,1.1-5.5
C894.8,51.7,818.3,2.1,733.9,2h-51.2c-2.7,0-5,2.2-5,5V8.6z"/>
<path class="st1" d="M676.5,133.7h-11.7c-2.2,0-4-1.8-4-4V118c0-1.1-0.9-2-2-2h-11.7c-2.2,0-4-1.8-4-4v-11.7c0-2.2,1.8-4,4-4h11.7
c1.1,0,2-0.9,2-2V82.8c0-2.2,1.8-4,4-4h11.7c2.2,0,4,1.8,4,4v11.7c0,1.1,0.9,2,2,2h11.7c2.2,0,4,1.8,4,4v11.7c0,2.2-1.8,4-4,4h-11.7
c-1.1,0-2,0.9-2,2v11.7C680.5,131.9,678.7,133.7,676.5,133.7z M647.2,98.5c-1.1,0-2,0.9-2,2v11.7c0,1.1,0.9,2,2,2h11.7
c2.2,0,4,1.8,4,4v11.7c0,1.1,0.9,2,2,2h11.7c1.1,0,2-0.9,2-2v-11.7c0-2.2,1.8-4,4-4h11.7c1.1,0,2-0.9,2-2v-11.7c0-1.1-0.9-2-2-2
h-11.7c-2.2,0-4-1.8-4-4V82.8c0-1.1-0.9-2-2-2h-11.7c-1.1,0-2,0.9-2,2v11.7c0,2.2-1.8,4-4,4H647.2z"/>
<path class="st1" d="M768.9,372.4c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C807.3,355.2,790.1,372.4,768.9,372.4z M768.9,297.5c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C805.3,313.8,789,297.5,768.9,297.5L768.9,297.5z"/>
<path class="st1" d="M768.9,225.5c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C807.3,208.3,790.1,225.5,768.9,225.5z M768.9,150.6c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C805.3,166.9,789,150.6,768.9,150.6L768.9,150.6z"/>
<path class="st1" d="M842.3,299c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C880.8,281.7,863.6,298.9,842.3,299z M842.3,224c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C878.8,240.4,862.5,224,842.3,224L842.3,224z"/>
<path class="st1" d="M695.5,299c-21.2,0-38.5-17.2-38.5-38.5c0-21.2,17.2-38.5,38.5-38.5c21.2,0,38.5,17.2,38.5,38.5
C733.9,281.7,716.7,298.9,695.5,299z M695.5,224c-20.1,0-36.5,16.3-36.5,36.5c0,20.1,16.3,36.5,36.5,36.5
c20.1,0,36.5-16.3,36.5-36.5C731.9,240.4,715.6,224,695.5,224L695.5,224z"/>
<path class="st1" d="M715,750.2c-16,0-28.9-13-28.9-28.9s13-28.9,28.9-28.9c16,0,28.9,13,28.9,28.9l0,0
C743.9,737.3,731,750.2,715,750.2z M715,694.3c-14.9,0-26.9,12.1-26.9,26.9s12.1,26.9,26.9,26.9c14.9,0,26.9-12.1,26.9-26.9
C741.9,706.4,729.9,694.4,715,694.3z"/>
<path class="st1" d="M705.8,533.4h-12.3c-0.6,0-1-0.4-1-1l0,0c1.7-39.6,33.4-71.3,73-73c0.3,0,0.5,0.1,0.7,0.3
c0.2,0.2,0.3,0.4,0.3,0.7v12.3c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9C712.2,530.8,709.3,533.4,705.8,533.4z
M694.6,531.4h11.2c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-11.2
C727.2,463.5,696.7,494,694.6,531.4z"/>
<path class="st1" d="M765.6,612.1C765.6,612.1,765.5,612.1,765.6,612.1c-39.6-1.7-71.3-33.4-73-73c0-0.6,0.4-1,1-1l0,0h12.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9v12.3C766.6,611.6,766.1,612.1,765.6,612.1L765.6,612.1
L765.6,612.1z M694.6,540c2.2,37.4,32.6,67.8,70,70v-11.2c0-2.5-1.8-4.6-4.3-4.9c-25.6-3.9-45.7-24-49.6-49.6
c-0.3-2.5-2.4-4.3-4.9-4.3H694.6z"/>
<path class="st1" d="M772.2,612.1c-0.6,0-1-0.4-1-1l0,0v-12.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9
c0.5-3.4,3.4-6,6.9-6h12.3c0.6,0,1,0.4,1,1l0,0C843.5,578.7,811.9,610.3,772.2,612.1C772.3,612.1,772.3,612.1,772.2,612.1z M832,540
c-2.5,0-4.6,1.8-4.9,4.3c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9V610c37.4-2.2,67.8-32.6,70-70H832z"/>
<path class="st1" d="M844.3,533.4H832c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-12.3
c0-0.3,0.1-0.5,0.3-0.7s0.5-0.3,0.7-0.3c39.6,1.7,71.3,33.4,73,73C845.3,532.9,844.9,533.3,844.3,533.4L844.3,533.4L844.3,533.4z
M773.2,461.4v11.2c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h11.2
C841.1,494,810.6,463.5,773.2,461.4z"/>
<path class="st1" d="M768.9,612.2c-1.2,0-2.3,0-3.4-0.1c-0.5,0-0.9-0.5-0.9-1v-12.3c0-2.5-1.8-4.6-4.3-4.9
c-25.6-3.9-45.7-24-49.6-49.6c-0.3-2.5-2.4-4.3-4.9-4.3h-12.3c-0.5,0-1-0.4-1-0.9c-0.1-1.1-0.1-2.2-0.1-3.4s0-2.3,0.1-3.4
c0-0.5,0.5-0.9,1-0.9h12.3c2.5,0,4.6-1.8,4.9-4.3c3.9-25.6,24-45.7,49.6-49.6c2.5-0.3,4.3-2.4,4.3-4.9v-12.3c0-0.5,0.4-1,0.9-1
c2.3-0.1,4.5-0.1,6.8,0c0.5,0,0.9,0.5,0.9,1v12.3c0,2.5,1.8,4.6,4.3,4.9c25.6,3.9,45.7,24,49.6,49.6c0.3,2.5,2.4,4.3,4.9,4.3h12.3
c0.5,0,1,0.4,1,0.9c0.1,1.1,0.1,2.2,0.1,3.4s0,2.3-0.1,3.4c0,0.5-0.5,0.9-1,0.9H832c-2.5,0-4.6,1.8-4.9,4.3
c-3.9,25.6-24,45.7-49.6,49.6c-2.5,0.3-4.3,2.4-4.3,4.9v12.3c0,0.5-0.4,1-0.9,1C771.2,612.1,770.1,612.2,768.9,612.2z M766.6,610.1
c1.5,0.1,3.1,0.1,4.7,0v-11.3c0-3.5,2.6-6.4,6-6.9c24.7-3.7,44.2-23.1,47.9-47.9c0.5-3.4,3.4-6,6.9-6h11.3c0-0.8,0-1.5,0-2.3
s0-1.6,0-2.3H832c-3.5,0-6.4-2.6-6.9-6c-3.7-24.7-23.1-44.2-47.9-47.9c-3.4-0.5-6-3.4-6-6.9v-11.3c-1.5-0.1-3.1-0.1-4.7,0v11.3
c0,3.5-2.6,6.4-6,6.9c-24.7,3.7-44.2,23.1-47.9,47.9c-0.5,3.4-3.4,6-6.9,6h-11.3c0,0.8,0,1.5,0,2.3s0,1.6,0,2.3h11.3
c3.5,0,6.4,2.6,6.9,6c3.7,24.7,23.1,44.2,47.9,47.9c3.4,0.5,6,3.4,6,6.9v11.3H766.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000.5" style="enable-background:new 0 0 1000 1000.5;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.1;}
.st1{fill:#1ABC9C;}
.st2{fill:#CCCCCC;}
.st3{fill:#FFFFFF;}
</style>
<g class="st0">
<path class="st1" d="M259.4,630.9c-22.4,12.5-32.3,39.7-49,69.8c-35.7,64.1-50.5,128.9-116.6,128.9C40.8,829.5,1,776.1,1,705.8
c0-48.3,29.9-226.9,55.6-347.6C113.4,453.9,219.5,604.4,259.4,630.9z"/>
<path class="st1" d="M999,705.8c0,70.4-39.9,123.8-92.7,123.8c-66.1,0-80.9-64.8-116.6-128.9c-16.7-30-26.7-57.3-49-69.8
c39.8-26.5,146-177,202.7-272.7C969.1,478.9,999,657.5,999,705.8z"/>
<circle class="st1" cx="630.3" cy="482.7" r="56.2"/>
<circle class="st1" cx="630.3" cy="482.7" r="40.5"/>
<circle class="st1" cx="764.9" cy="276.6" r="36.6"/>
<circle class="st1" cx="764.9" cy="412.6" r="36.6"/>
<circle class="st1" cx="223.9" cy="344.8" r="56.2"/>
<circle class="st1" cx="223.9" cy="344.8" r="40.5"/>
<circle class="st1" cx="843.1" cy="344.6" r="36.6"/>
<circle class="st1" cx="686.7" cy="344.6" r="36.6"/>
<circle class="st1" cx="624.1" cy="269.3" r="22.1"/>
<circle class="st1" cx="571.3" cy="344.6" r="22.1"/>
<circle class="st1" cx="375.9" cy="269.3" r="22.1"/>
<circle class="st1" cx="428.7" cy="344.6" r="14"/>
<path class="st1" d="M414.6,326.5h28.2c2.2,0,4.1,1.8,4.1,4.1v28.2c0,2.2-1.8,4.1-4.1,4.1h-28.2c-2.2,0-4.1-1.8-4.1-4.1v-28.2
C410.6,328.3,412.4,326.5,414.6,326.5z"/>
<path class="st1" d="M351.6,158.8c-88.4,3.8-169.6,13.7-207,39.4c-14.9,10.2-26.4,16.9-32.9,20.5C142.6,135.9,282,138,299,138
c6.5,0,26.6,8.7,39.9,14.8h0C346.3,156.2,351.6,158.8,351.6,158.8z"/>
<path class="st1" d="M888.3,218.7c-6.5-3.6-18-10.3-32.9-20.6c-37.4-25.7-118.7-35.6-207-39.4c0,0,5.3-2.6,12.6-6
c13.4-6.1,33.4-14.8,40-14.8C717.9,138,857.4,135.9,888.3,218.7z"/>
<path class="st1" d="M414.6,461.1H373c-2.2,0-4.1-1.8-4.1-4.1v-41.6c0-2.2-1.8-4.1-4.1-4.1c0,0,0,0,0,0h-36.4
c-2.2,0-4.1,1.8-4.1,4.1c0,0,0,0,0,0v41.6c0,2.2-1.8,4.1-4.1,4.1h-41.6c-2.2,0-4.1,1.8-4.1,4.1v36.4c0,2.2,1.8,4.1,4.1,4.1h41.6
c2.2,0,4.1,1.8,4.1,4.1l0,0v41.6c0,2.2,1.8,4.1,4.1,4.1c0,0,0,0,0,0h36.4c2.2,0,4.1-1.8,4.1-4.1l0,0v-41.6c0-2.2,1.8-4.1,4.1-4.1
l0,0h41.6c2.2,0,4.1-1.8,4.1-4.1v-36.4C418.6,462.9,416.8,461.1,414.6,461.1z"/>
</g>
<path class="st2" d="M661,153.1L661,153.1c-0.2,0-0.3-0.1-0.3-0.3c0-0.1,0.1-0.2,0.2-0.2c0.1,0,0.3,0.1,0.3,0.2
C661.3,153,661.2,153.1,661,153.1C661,153.1,661,153.1,661,153.1z"/>
<path class="st3" d="M630.3,560.6c-43,0-77.9-34.9-77.9-77.9s34.9-77.9,77.9-77.9c43,0,77.9,34.9,77.9,77.9
C708.2,525.7,673.3,560.6,630.3,560.6z M630.3,405.8c-42.5,0-76.9,34.4-76.9,76.9s34.4,76.9,76.9,76.9c42.5,0,76.9-34.4,76.9-76.9
C707.2,440.3,672.8,405.9,630.3,405.8L630.3,405.8z"/>
<path class="st3" d="M223.9,422.7c-43,0-77.9-34.9-77.9-77.9c0-43,34.9-77.9,77.9-77.9s77.9,34.9,77.9,77.9l0,0
C301.7,387.8,266.9,422.7,223.9,422.7z M223.9,267.9c-42.5,0-76.9,34.4-76.9,76.9c0,42.5,34.4,76.9,76.9,76.9s76.9-34.4,76.9-76.9
l0,0C300.7,302.4,266.3,268,223.9,267.9z"/>
<path class="st3" d="M648.4,159.3L648.4,159.3c-49.9-2.1-102.8-2.3-148.4-2.3c-45.6,0-98.4,0.2-148.4,2.3c-0.1,0-0.2,0-0.2-0.1
c-0.1,0-5.4-2.6-12.6-6c-0.3-0.1-0.4-0.4-0.2-0.7c0.1-0.2,0.2-0.3,0.4-0.3c2-0.2,50-4.9,161.1-4.9c111.7,0,159.1,4.7,161,4.9
c0.3,0,0.5,0.3,0.4,0.5c0,0.2-0.1,0.3-0.3,0.4c-7.2,3.3-12.6,5.9-12.6,6C648.5,159.3,648.4,159.3,648.4,159.3z M340.9,153.2
c5.8,2.7,10.1,4.8,10.8,5.1c49.9-2.1,102.7-2.3,148.3-2.3c45.6,0,98.4,0.2,148.3,2.3c0.7-0.4,5-2.4,10.8-5.1
c-9.8-0.9-58.2-4.7-159.1-4.7C399.6,148.5,350.7,152.3,340.9,153.2L340.9,153.2z"/>
<path class="st3" d="M740.6,631.4c-0.1,0-0.2,0-0.2-0.1c-8.6-4.8-18.6-7.2-30.7-7.2H290.3c-12,0-22.1,2.4-30.7,7.2
c-0.2,0.1-0.4,0.1-0.5,0C218.3,604.2,110,449.1,56.2,358.4c-0.1-0.1-0.1-0.2-0.1-0.4c11.3-53.3,20.7-90,27.1-106.1
c1.2-3.1,2.9-5.9,4.9-8.5l12.7-16.2c2.9-3.7,6.5-6.8,10.6-9c0,0,0,0,0,0l0,0c7.1-3.9,18.5-10.6,32.8-20.5
c32-22,99.8-34.9,207.3-39.4c49.5-2.1,100.5-2.3,148.4-2.3c47.9,0,98.8,0.2,148.4,2.3c107.5,4.6,175.3,17.5,207.3,39.4
c14.4,9.9,25.8,16.6,32.9,20.5c4.1,2.2,7.7,5.3,10.6,9l12.7,16.2c2.1,2.6,3.7,5.5,4.9,8.6c6.4,16.1,15.7,52.8,27.1,106.1
c0,0.1,0,0.3-0.1,0.4C890,449.1,781.7,604.2,740.9,631.3C740.8,631.4,740.7,631.4,740.6,631.4z M57.2,358.1
c53.6,90.4,161.4,244.7,202.2,272.2c8.7-4.8,18.8-7.2,30.9-7.2h419.4c12.1,0,22.2,2.3,30.9,7.2c40.8-27.5,148.6-181.8,202.2-272.2
c-11.3-53.1-20.6-89.7-27-105.7c-1.2-3-2.8-5.8-4.8-8.3l-12.7-16.2c-2.8-3.6-6.3-6.5-10.3-8.7c-7.1-3.9-18.5-10.7-33-20.6
c-31.8-21.9-99.4-34.7-206.8-39.3c-49.5-2.1-100.4-2.3-148.3-2.3c-47.9,0-98.8,0.2-148.4,2.3c-107.3,4.6-174.9,17.4-206.7,39.3
c-14.4,9.9-25.8,16.6-32.9,20.5c0,0-0.1,0-0.1,0.1c-4,2.2-7.5,5.2-10.3,8.7l-12.7,16.2c-2,2.5-3.6,5.3-4.8,8.3
C77.8,268.4,68.5,305,57.2,358.1z"/>
<path class="st1" d="M93.7,830.5C40.3,830.5,0,776.9,0,705.8C0,657.1,29.9,478.8,55.6,358c0.1-0.5,0.6-0.9,1.2-0.8
c0.3,0.1,0.5,0.2,0.7,0.5c53.7,90.5,161.9,245.4,202.4,272.4c0.5,0.3,0.6,0.9,0.3,1.4c-0.1,0.1-0.2,0.2-0.3,0.3
c-17.4,9.7-27.3,28.8-38.8,50.9c-3.1,6-6.3,12.1-9.8,18.4c-7.3,13.1-13.7,26.1-19.8,38.7C167.5,788.5,146.9,830.5,93.7,830.5z
M57.1,360.9C31.5,481.6,2,657.5,2,705.8c0,70,39.4,122.8,91.7,122.8c52,0,72.3-41.5,95.9-89.6c6.2-12.6,12.6-25.7,19.9-38.8
c3.5-6.3,6.7-12.4,9.8-18.4c11.3-21.8,21.2-40.7,38.2-51C216.1,601.5,110.7,450.9,57.1,360.9z"/>
<path class="st1" d="M906.3,830.5c-53.3,0-73.9-42-97.7-90.7c-6.2-12.6-12.5-25.6-19.8-38.7c-3.5-6.3-6.7-12.5-9.8-18.4
c-11.5-22.1-21.4-41.2-38.8-50.9c-0.5-0.3-0.7-0.9-0.4-1.4c0.1-0.1,0.2-0.3,0.3-0.3c40.6-27,148.7-181.8,202.4-272.4
c0.3-0.5,0.9-0.6,1.4-0.3c0.2,0.1,0.4,0.4,0.5,0.7c25.7,120.9,55.6,299.1,55.6,347.8C1000,776.9,959.7,830.5,906.3,830.5z
M742.5,630.8c17.1,10.2,26.9,29.2,38.2,51c3.1,6,6.3,12.1,9.8,18.4c7.3,13.1,13.7,26.1,19.9,38.7c23.5,48.1,43.9,89.6,95.9,89.6
c52.3,0,91.7-52.8,91.7-122.8c0-48.2-29.5-224.2-55.1-344.9C889.3,450.9,783.9,601.5,742.5,630.8z"/>
<path class="st1" d="M630.3,539.9c-31.6,0-57.2-25.6-57.2-57.2c0-31.6,25.6-57.2,57.2-57.2c31.6,0,57.2,25.6,57.2,57.2l0,0
C687.5,514.3,661.9,539.9,630.3,539.9z M630.3,427.5c-30.5,0-55.2,24.7-55.2,55.2c0,30.5,24.7,55.2,55.2,55.2
c30.5,0,55.2-24.7,55.2-55.2C685.5,452.2,660.8,427.5,630.3,427.5L630.3,427.5z"/>
<path class="st1" d="M630.3,524.2c-22.9,0-41.5-18.6-41.5-41.5s18.6-41.5,41.5-41.5c22.9,0,41.5,18.6,41.5,41.5
C671.8,505.6,653.2,524.2,630.3,524.2z M630.3,443.2c-21.8,0-39.5,17.7-39.5,39.5c0,21.8,17.7,39.5,39.5,39.5
c21.8,0,39.5-17.7,39.5-39.5C669.8,460.9,652.1,443.2,630.3,443.2z"/>
<path class="st1" d="M764.9,314.2c-20.7,0-37.6-16.8-37.5-37.6c0-20.7,16.8-37.6,37.6-37.5c20.7,0,37.5,16.8,37.5,37.6
C802.4,297.4,785.6,314.1,764.9,314.2z M764.9,241.1c-19.6,0-35.6,15.9-35.6,35.6c0,19.6,15.9,35.6,35.6,35.6
c19.6,0,35.6-15.9,35.6-35.6C800.4,257,784.5,241.1,764.9,241.1L764.9,241.1z"/>
<path class="st1" d="M764.9,450.2c-20.7,0-37.6-16.8-37.5-37.6c0-20.7,16.8-37.6,37.6-37.5c20.7,0,37.5,16.8,37.5,37.6
C802.4,433.4,785.6,450.2,764.9,450.2z M764.9,377.1c-19.6,0-35.6,15.9-35.6,35.6c0,19.6,15.9,35.6,35.6,35.6
c19.6,0,35.6-15.9,35.6-35.6C800.4,393,784.5,377.1,764.9,377.1z"/>
<path class="st1" d="M223.9,402.1c-31.6,0-57.2-25.6-57.2-57.2c0-31.6,25.6-57.2,57.2-57.2s57.2,25.6,57.2,57.2
C281.1,376.4,255.5,402,223.9,402.1z M223.9,289.6c-30.5,0-55.2,24.7-55.2,55.2c0,30.5,24.7,55.2,55.2,55.2
c30.5,0,55.2-24.7,55.2-55.2c0,0,0,0,0,0C279.1,314.4,254.4,289.7,223.9,289.6L223.9,289.6z"/>
<path class="st1" d="M223.9,386.4c-22.9,0-41.5-18.6-41.5-41.5c0-22.9,18.6-41.5,41.5-41.5s41.5,18.6,41.5,41.5
C265.4,367.8,246.8,386.3,223.9,386.4z M223.9,305.3c-21.8,0-39.5,17.7-39.5,39.5c0,21.8,17.7,39.5,39.5,39.5s39.5-17.7,39.5-39.5
l0,0C263.4,323,245.7,305.3,223.9,305.3L223.9,305.3z"/>
<path class="st1" d="M843.1,382.2c-20.7,0-37.6-16.8-37.6-37.5s16.8-37.6,37.5-37.6c20.7,0,37.6,16.8,37.6,37.5c0,0,0,0,0,0
C880.6,365.4,863.8,382.2,843.1,382.2z M843.1,309.1c-19.6,0-35.6,15.9-35.6,35.6s15.9,35.6,35.6,35.6c19.6,0,35.6-15.9,35.6-35.6
c0,0,0,0,0,0C878.6,325,862.7,309.1,843.1,309.1z"/>
<path class="st1" d="M686.7,382.2c-20.7,0-37.6-16.8-37.6-37.6s16.8-37.6,37.6-37.6c20.7,0,37.6,16.8,37.6,37.6
C724.2,365.4,707.4,382.2,686.7,382.2z M686.7,309.1c-19.6,0-35.6,15.9-35.6,35.6s15.9,35.6,35.6,35.6c19.6,0,35.6-15.9,35.6-35.6
l0,0C722.2,325,706.3,309.1,686.7,309.1z"/>
<path class="st1" d="M624.1,292.4c-12.8,0-23.1-10.3-23.1-23.1c0-12.8,10.3-23.1,23.1-23.1c12.8,0,23.1,10.3,23.1,23.1
C647.2,282,636.8,292.4,624.1,292.4z M624.1,248.2c-11.7,0-21.1,9.5-21.1,21.1c0,11.7,9.5,21.1,21.1,21.1c11.7,0,21.1-9.5,21.1-21.1
C645.2,257.6,635.7,248.2,624.1,248.2z"/>
<path class="st1" d="M571.3,367.7c-12.8,0-23.1-10.3-23.1-23.1c0-12.8,10.3-23.1,23.1-23.1c12.8,0,23.1,10.3,23.1,23.1
C594.3,357.4,584,367.7,571.3,367.7z M571.3,323.5c-11.7,0-21.1,9.5-21.1,21.1c0,11.7,9.5,21.1,21.1,21.1c11.7,0,21.1-9.5,21.1-21.1
C592.3,333,582.9,323.5,571.3,323.5L571.3,323.5z"/>
<path class="st1" d="M375.9,292.4c-12.8,0-23.1-10.3-23.1-23.1c0-12.8,10.3-23.1,23.1-23.1c12.8,0,23.1,10.3,23.1,23.1
C399,282,388.7,292.4,375.9,292.4z M375.9,248.2c-11.7,0-21.1,9.5-21.1,21.1c0,11.7,9.5,21.1,21.1,21.1c11.7,0,21.1-9.5,21.1-21.1
C397,257.6,387.6,248.2,375.9,248.2z"/>
<path class="st1" d="M428.7,359.6c-8.3,0-15-6.7-15-15s6.7-15,15-15s15,6.7,15,15l0,0C443.7,352.9,437,359.6,428.7,359.6z
M428.7,331.7c-7.2,0-13,5.8-13,13c0,7.2,5.8,13,13,13c7.2,0,13-5.8,13-13c0,0,0,0,0,0C441.7,337.5,435.9,331.7,428.7,331.7
L428.7,331.7z"/>
<path class="st1" d="M442.8,363.8h-28.2c-2.8,0-5.1-2.3-5.1-5.1v-28.2c0-2.8,2.3-5.1,5.1-5.1h28.2c2.8,0,5.1,2.3,5.1,5.1v28.2
C447.9,361.5,445.6,363.8,442.8,363.8z M414.6,327.5c-1.7,0-3.1,1.4-3.1,3.1v28.2c0,1.7,1.4,3.1,3.1,3.1h28.2c1.7,0,3.1-1.4,3.1-3.1
v-28.2c0-1.7-1.4-3.1-3.1-3.1H414.6z"/>
<path class="st1" d="M111.7,219.7c-0.6,0-1-0.4-1-1c0-0.1,0-0.2,0.1-0.3c27.3-73.2,138.4-81.3,186-81.3c0.3,0,0.6,0,1,0l1.2,0
c6.6,0,25.5,8.1,40.3,14.9c0,0,0.1,0,0.1,0c7.2,3.3,12.6,6,12.7,6c0.5,0.2,0.7,0.8,0.5,1.3c-0.2,0.3-0.5,0.5-0.9,0.6
c-107.2,4.6-174.8,17.4-206.5,39.2c-14.6,10-26,16.7-33,20.6C112.1,219.6,111.9,219.7,111.7,219.7z M296.8,139
c-46.6,0-154.6,7.8-183.1,77.5c7-4,17.5-10.3,30.4-19.1c31.6-21.7,98.2-34.6,203.6-39.4c-2.2-1.1-5.4-2.5-8.9-4.2c0,0-0.1,0-0.1,0
c-20.6-9.5-34.7-14.7-39.5-14.7l-1.2,0C297.5,139,297.1,139,296.8,139L296.8,139z"/>
<path class="st1" d="M888.3,219.7c-0.2,0-0.3,0-0.5-0.1c-7-3.9-18.5-10.7-33-20.6c-31.7-21.8-99.3-34.6-206.5-39.2c-0.6,0-1-0.5-1-1
c0-0.4,0.2-0.7,0.6-0.9c0.1,0,5.4-2.6,12.7-6C682.2,142,695.8,137,701,137l1.2,0c0.3,0,0.6,0,1,0c47.6,0,158.7,8.1,186.1,81.4
c0.2,0.5-0.1,1.1-0.6,1.3C888.5,219.7,888.4,219.7,888.3,219.7L888.3,219.7z M652.4,158c105.3,4.7,171.9,17.6,203.6,39.4
c12.9,8.8,23.3,15.1,30.4,19.1C857.8,146.8,749.8,139,703.2,139c-0.3,0-0.6,0-1,0l-1.2,0c-4.8,0-18.8,5.2-39.5,14.7
C657.8,155.4,654.6,156.9,652.4,158z"/>
<path class="st1" d="M364.9,556.4h-36.4c-2.8,0-5.1-2.3-5.1-5.1v-41.6c0-1.7-1.4-3.1-3.1-3.1h-41.6c-2.8,0-5.1-2.3-5.1-5.1v-36.4
c0-2.8,2.3-5.1,5.1-5.1h41.6c1.7,0,3.1-1.4,3.1-3.1v-41.6c0-2.8,2.3-5.1,5.1-5.1h36.4c2.8,0,5.1,2.3,5.1,5.1v41.6
c0,1.7,1.4,3.1,3.1,3.1h41.6c2.8,0,5.1,2.3,5.1,5.1v36.4c0,2.8-2.3,5.1-5.1,5.1H373c-1.7,0-3.1,1.4-3.1,3.1v41.6
C369.9,554.1,367.7,556.4,364.9,556.4z M278.8,462.1c-1.7,0-3.1,1.4-3.1,3.1v36.4c0,1.7,1.4,3.1,3.1,3.1h41.6c2.8,0,5.1,2.3,5.1,5.1
v41.6c0,1.7,1.4,3.1,3.1,3.1h36.4c1.7,0,3.1-1.4,3.1-3.1v-41.6c0-2.8,2.3-5.1,5.1-5.1h41.6c1.7,0,3.1-1.4,3.1-3.1v-36.4
c0-1.7-1.4-3.1-3.1-3.1H373c-2.8,0-5.1-2.3-5.1-5.1v-41.6c0-1.7-1.4-3.1-3.1-3.1h-36.4c-1.7,0-3.1,1.4-3.1,3.1v41.6
c0,2.8-2.3,5.1-5.1,5.1H278.8z"/>
<rect x="363.7" y="267.5" class="st1" width="24.4" height="3.5"/>
<polygon class="st1" points="636.3,267.5 625.8,267.5 625.8,257.1 622.3,257.1 622.3,267.5 611.9,267.5 611.9,271 622.3,271
622.3,281.4 625.8,281.4 625.8,271 636.3,271 "/>
<path class="st1" d="M775.5,289.9H771l-6.3-10.4l-6.3,10.4h-4.4l8.6-13.2l-7.9-12.6h4.2l5.9,9.7l5.9-9.7h4l-7.9,12.4L775.5,289.9z"
/>
<path class="st1" d="M697.8,331.8l-9.3,16.5v9.2h-3.5v-9.3l-9.3-16.5h4.2l5.1,9.4l1.9,3.8l1.7-3.4l5.2-9.8L697.8,331.8z"/>
<path class="st1" d="M854,357.5h-3.8l-1.8-5.6h-10.7l-1.8,5.6h-3.6l8.5-25.7h4.8L854,357.5z M847.4,348.8L843,335l-4.4,13.8H847.4z"
/>
<path class="st1" d="M773.3,417.8c0,1.1-0.2,2.3-0.7,3.3c-0.5,1-1.2,1.8-2,2.4c-1,0.7-2.1,1.2-3.2,1.5c-1.4,0.4-2.8,0.5-4.2,0.5
h-6.7v-25.7h7.4c5.7,0,8.6,2.1,8.6,6.3c0,1.3-0.3,2.5-1,3.6c-0.8,1.1-1.9,1.9-3.2,2.2c0.7,0.1,1.4,0.4,2,0.7
c0.6,0.3,1.2,0.7,1.6,1.2c0.5,0.5,0.9,1.1,1.1,1.8C773.2,416.2,773.4,417,773.3,417.8z M768.8,406.5c0-0.5-0.1-1-0.2-1.5
c-0.2-0.5-0.4-0.9-0.8-1.2c-0.5-0.4-1-0.6-1.6-0.8c-0.8-0.2-1.7-0.3-2.5-0.3H760v8.1h3.5c0.7,0,1.5-0.1,2.2-0.3
c0.6-0.1,1.2-0.4,1.7-0.8c0.5-0.3,0.8-0.8,1.1-1.3C768.7,407.8,768.8,407.2,768.8,406.5L768.8,406.5z M769.6,417.9
c0-0.6-0.1-1.2-0.4-1.8c-0.3-0.5-0.7-1-1.2-1.3c-0.6-0.4-1.2-0.7-1.9-0.8c-0.8-0.2-1.7-0.3-2.5-0.3H760v8.9h3.7
c1.6,0.1,3.2-0.3,4.5-1.1C769.2,420.6,769.7,419.3,769.6,417.9L769.6,417.9z"/>
<path class="st1" d="M571.3,329.3L557.7,343h3.9v11.6h19.5V343h3.7L571.3,329.3z M575.2,350.4h-7.7V343h7.7L575.2,350.4z"/>
<polygon class="st1" points="346.7,426.4 339.2,439.4 354.2,439.4 "/>
<polygon class="st1" points="346.7,540.4 339.2,527.4 354.2,527.4 "/>
<polygon class="st1" points="403.7,483.4 390.7,475.9 390.7,490.9 "/>
<polygon class="st1" points="289.6,483.4 302.6,475.9 302.6,490.9 "/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

View File

@ -840,8 +840,8 @@
"title": "Joystick Deadzone",
"description": "Controller Analog Stick Deadzone",
"default": 0.05,
"minimum": -32768.0,
"maximum": 32767.0,
"minimum": 0.00,
"maximum": 1.00,
"examples": [
0.05
]