mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-25 05:58:35 +01:00
Compare commits
82 commits
c1d1c03063
...
a1c5b8e2d6
Author | SHA1 | Date | |
---|---|---|---|
a1c5b8e2d6 | |||
a7c6230434 | |||
4854d420e0 | |||
393bd9ffe5 | |||
30b4d5fc43 | |||
df0ad68837 | |||
37f0470e4f | |||
94dec34470 | |||
6a3c797eba | |||
3ad024b95a | |||
ae6ce6e7d5 | |||
54ca580dd3 | |||
4e122175b2 | |||
c6fe72bdc9 | |||
bb7192b3cc | |||
c5b2b8798e | |||
1f4f0cfa44 | |||
4aff5a2875 | |||
bb22bbdf75 | |||
fa34258bbe | |||
8fa94f1186 | |||
d5f3453c71 | |||
35e3896dc1 | |||
5d97ab033f | |||
b77edd80d5 | |||
f166c3d256 | |||
2c90ca9b89 | |||
cd32372994 | |||
0f4e67f20f | |||
96f0c51757 | |||
180f82d2c7 | |||
|
2d3e291431 | ||
|
9e8ff82579 | ||
7c18aad8f7 | |||
a14a37cb91 | |||
45955bb5e8 | |||
cb8fed87e5 | |||
67388c106b | |||
48a4aa0588 | |||
d5ec0b8001 | |||
b260aa6901 | |||
af7c341d83 | |||
c360c90f28 | |||
856d69b7db | |||
3a275a1820 | |||
2dcd5c3fa7 | |||
0918e1700b | |||
48b96a10a4 | |||
ad2784a67e | |||
ab76ea5ba8 | |||
ed88862194 | |||
c880c3e011 | |||
a143aef67c | |||
dc6c472b84 | |||
3c4567e4a1 | |||
f7cf9460d6 | |||
c7f021e62d | |||
f3e6df6862 | |||
94b6aa0d1b | |||
faa400c4e6 | |||
dbf370c968 | |||
58a0f8915a | |||
3edd593886 | |||
9ccb3536a0 | |||
6b81054159 | |||
80a6c6b5e2 | |||
c28f6d858c | |||
68fc02b170 | |||
6e75e9ebb4 | |||
b46975391b | |||
a61d7a9722 | |||
2699d0e1c2 | |||
04fab568f8 | |||
b2b34abcd0 | |||
29bbd61f8b | |||
b4f79f0753 | |||
7e49eaef10 | |||
5d9cccc9fd | |||
c060d78010 | |||
f5adf50823 | |||
17ed82fc3c | |||
7f3abdada5 |
94 changed files with 2433 additions and 1164 deletions
85
CHANGELOG.md
85
CHANGELOG.md
|
@ -2,10 +2,95 @@
|
||||||
MLEM tries to adhere to [semantic versioning](https://semver.org/). Breaking changes are written in **bold**.
|
MLEM tries to adhere to [semantic versioning](https://semver.org/). Breaking changes are written in **bold**.
|
||||||
|
|
||||||
Jump to version:
|
Jump to version:
|
||||||
|
- [5.3.0](#530)
|
||||||
- [5.2.0](#520)
|
- [5.2.0](#520)
|
||||||
- [5.1.0](#510)
|
- [5.1.0](#510)
|
||||||
- [5.0.0](#500)
|
- [5.0.0](#500)
|
||||||
|
|
||||||
|
## 5.3.0
|
||||||
|
### MLEM
|
||||||
|
Additions
|
||||||
|
- Added StringBuilder overloads to GenericFont
|
||||||
|
- Added ColorExtensions.Multiply
|
||||||
|
- Added SoundEffectInstanceHandler.Stop
|
||||||
|
- Added TextureRegion.OffsetCopy
|
||||||
|
- Added RectangleF.DistanceSquared and RectangleF.Distance
|
||||||
|
- Added GamepadExtensions.GetAnalogValue to get the analog value of any gamepad button
|
||||||
|
- Added InputHandler.TryGetDownTime
|
||||||
|
|
||||||
|
Improvements
|
||||||
|
- Generify GenericFont's string drawing
|
||||||
|
- Added InputHandler mouse and touch position querying that preserves the game's viewport
|
||||||
|
- Added float version of GetRandomWeightedEntry
|
||||||
|
- Allow LinkCode to specify a color to draw with
|
||||||
|
- Allow better control over the order and layout of a Keybind's combinations
|
||||||
|
- Allow setting a gamepad button deadzone in InputHandler
|
||||||
|
- Trigger InputHandler key and gamepad repeats for the most recently pressed input
|
||||||
|
- Added properties and constructors for existing operator overloads to GenericInput
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
- **Fixed a formatting Code only knowing about the last Token that it is applied in**
|
||||||
|
- Fixed Code.Draw receiving the index in the current line rather than the current token
|
||||||
|
- Fixed StaticSpriteBatch handling rotated sprites incorrectly
|
||||||
|
- Fixed InputHandler.InputsPressed ignoring repeat events for keyboards and gamepads
|
||||||
|
|
||||||
|
Removals
|
||||||
|
- **Removed InputHandler.StoreAllActiveInputs and always store all active inputs**
|
||||||
|
- Renamed GenericFont.OneEmSpace to Emsp (and marked OneEmSpace as obsolete)
|
||||||
|
|
||||||
|
### MLEM.Ui
|
||||||
|
Additions
|
||||||
|
- Added Element.OnStyleInit event
|
||||||
|
- Added UiControls.AutoNavModeChanged event
|
||||||
|
|
||||||
|
Improvements
|
||||||
|
- Allow for checkboxes and radio buttons to be disabled
|
||||||
|
- Only set a paragraph's area dirty when a text change would cause it to change size
|
||||||
|
- Ensure that a panel gets notified of all relevant changes by calling OnChildAreaDirty for all grandchildren
|
||||||
|
- Avoid unnecessary panel updates by using an Epsilon comparison when scrolling children
|
||||||
|
- Allow setting a default text alignment for paragraphs in UiStyle
|
||||||
|
- Made custom values of Element.Style persist when a new ui style is set
|
||||||
|
- Update elements less aggressively when changing a ui system's style
|
||||||
|
- Automatically update all elements when changing a ui system's viewport
|
||||||
|
- Allow setting a default color for clickable links in UiStyle
|
||||||
|
- Allow ElementHelper's KeybindButton to query a combination at a given index
|
||||||
|
- Allow ElementHelper's KeybindButton to accept a Keybind for clearing a combination
|
||||||
|
- Automatically select the first element when a dropdown is opened in auto nav mode
|
||||||
|
- Improved gamepad navigation by employing angles between elements
|
||||||
|
- Prefer elements that have the same parent as the currently selected element when using gamepad navigation
|
||||||
|
- Allow specifying a custom position for a tooltip to snap to
|
||||||
|
- Allow tooltips to display for elements when selected in auto-nav mode
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
- Fixed paragraph links having incorrect hover locations when using special text alignments
|
||||||
|
- Fixed the graphics device's viewport being ignored for mouse and touch queries
|
||||||
|
- Fixed auto-navigating panels not scrolling to the center of elements properly
|
||||||
|
- Fixed UiControls allowing for non-selectable or non-mouseable elements to be marked as selected or moused
|
||||||
|
- Fixed buttons and checkboxes changing their CanBeSelected and CanBePressed values when being disabled
|
||||||
|
- Fixed children of Panel scroll bars also being scrolled
|
||||||
|
- Fixed RootElement.CanSelectContent and Element.IsSelected returning incorrect results when CanBeSelected changes
|
||||||
|
- Fixed dropdowns with some non-selectable children failing to navigate when using gamepad controls
|
||||||
|
- Fixed UiMetrics.ForceAreaUpdateTime being inaccurate for nested elements
|
||||||
|
- Fixed tooltips sometimes ignoring manually set IsHidden values
|
||||||
|
- Fixed delayed tooltips sometimes displaying in the wrong location for one frame
|
||||||
|
|
||||||
|
Removals
|
||||||
|
- Marked StyleProp equality members as obsolete
|
||||||
|
- Marked Element.BeginDelegate and Element.BeginImpl as obsolete
|
||||||
|
- Marked Element.DrawEarly and UiSystem.DrawEarly as obsolete
|
||||||
|
|
||||||
|
### MLEM.Extended
|
||||||
|
Improvements
|
||||||
|
- Preserve texture region names when converting between MLEM and MG.Extended
|
||||||
|
|
||||||
|
### MLEM.Data
|
||||||
|
Improvements
|
||||||
|
- Rethrow exceptions when no RawContentManager readers could be constructed
|
||||||
|
- Make Newtonsoft.Json dependency optional
|
||||||
|
|
||||||
|
Removals
|
||||||
|
- Marked CopyExtensions as obsolete
|
||||||
|
|
||||||
## 5.2.0
|
## 5.2.0
|
||||||
### MLEM
|
### MLEM
|
||||||
Additions
|
Additions
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
|
using static Android.Views.SystemUiFlags;
|
||||||
|
|
||||||
namespace Demos.Android {
|
namespace Demos.Android {
|
||||||
[Activity(
|
[Activity(
|
||||||
|
@ -46,7 +47,8 @@ namespace Demos.Android {
|
||||||
public override void OnWindowFocusChanged(bool hasFocus) {
|
public override void OnWindowFocusChanged(bool hasFocus) {
|
||||||
base.OnWindowFocusChanged(hasFocus);
|
base.OnWindowFocusChanged(hasFocus);
|
||||||
// hide the status bar
|
// hide the status bar
|
||||||
this.view.SystemUiVisibility = (StatusBarVisibility) (SystemUiFlags.LayoutStable | SystemUiFlags.LayoutHideNavigation | SystemUiFlags.LayoutFullscreen | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen | SystemUiFlags.ImmersiveSticky);
|
if (hasFocus)
|
||||||
|
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (ImmersiveSticky | LayoutStable | LayoutHideNavigation | LayoutFullscreen | HideNavigation | Fullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,14 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||||
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
||||||
|
<AotAssemblies>false</AotAssemblies>
|
||||||
|
<EnableLLVM>false</EnableLLVM>
|
||||||
|
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
||||||
|
<BundleAssemblies>false</BundleAssemblies>
|
||||||
|
<MandroidI18n />
|
||||||
|
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
||||||
|
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||||
|
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
@ -75,22 +83,22 @@
|
||||||
<PackageReference Include="TextCopy" Version="4.3.0" />
|
<PackageReference Include="TextCopy" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Demos\Demos.csproj">
|
<ProjectReference Include="..\Demos\Demos.csproj">
|
||||||
<Project>{1bc4682b-aa14-4937-b5c7-707e20fe88ff}</Project>
|
<Project>{1bc4682b-aa14-4937-b5c7-707e20fe88ff}</Project>
|
||||||
<Name>Demos</Name>
|
<Name>Demos</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj">
|
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj">
|
||||||
<Project>{997f4739-7bec-4621-b9ca-68deb2d74412}</Project>
|
<Project>{997f4739-7bec-4621-b9ca-68deb2d74412}</Project>
|
||||||
<Name>MLEM.Startup</Name>
|
<Name>MLEM.Startup</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj">
|
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj">
|
||||||
<Project>{6f00629a-8b87-4264-8896-19983285e32f}</Project>
|
<Project>{6f00629a-8b87-4264-8896-19983285e32f}</Project>
|
||||||
<Name>MLEM.Ui</Name>
|
<Name>MLEM.Ui</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj">
|
<ProjectReference Include="..\MLEM\MLEM.csproj">
|
||||||
<Project>{1d6ab762-43c4-4775-8924-707c7ec3f142}</Project>
|
<Project>{1d6ab762-43c4-4775-8924-707c7ec3f142}</Project>
|
||||||
<Name>MLEM</Name>
|
<Name>MLEM</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.mlem.demos.android" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.mlem.demos.android" android:versionCode="1" android:versionName="1.0">
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
||||||
<application android:label="MLEM Android Demos" />
|
<application android:label="MLEM Android Demos" android:resizeableActivity="true" />
|
||||||
</manifest>
|
</manifest>
|
|
@ -12,17 +12,4 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
|
@ -1,25 +1,25 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||||
<AssemblyName>MLEM Desktop Demos</AssemblyName>
|
<AssemblyName>MLEM Desktop Demos</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Demos\Demos.csproj" />
|
<ProjectReference Include="..\Demos\Demos.csproj" />
|
||||||
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
||||||
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MonoGameContentReference Include="..\Demos\Content\Content.mgcb" />
|
<MonoGameContentReference Include="..\Demos\Content\Content.mgcb" />
|
||||||
<Content Include="..\Demos\Content\*\**" />
|
<Content Include="..\Demos\Content\*\**" />
|
||||||
<EmbeddedResource Include="Icon.ico" />
|
<EmbeddedResource Include="Icon.ico" />
|
||||||
|
|
|
@ -16,8 +16,7 @@ namespace Demos {
|
||||||
private Group buttons;
|
private Group buttons;
|
||||||
private bool stop;
|
private bool stop;
|
||||||
|
|
||||||
public AnimationDemo(MlemGame game) : base(game) {
|
public AnimationDemo(MlemGame game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
public override void LoadContent() {
|
public override void LoadContent() {
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
|
|
|
@ -15,8 +15,7 @@ namespace Demos {
|
||||||
private Texture2D texture;
|
private Texture2D texture;
|
||||||
private string[] layout;
|
private string[] layout;
|
||||||
|
|
||||||
public AutoTilingDemo(MlemGame game) : base(game) {
|
public AutoTilingDemo(MlemGame game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
public override void LoadContent() {
|
public override void LoadContent() {
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
|
|
|
@ -19,17 +19,13 @@ namespace Demos {
|
||||||
this.Game = game;
|
this.Game = game;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void LoadContent() {
|
public virtual void LoadContent() {}
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Update(GameTime time) {
|
public virtual void Update(GameTime time) {}
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void DoDraw(GameTime time) {
|
public virtual void DoDraw(GameTime time) {}
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Clear() {
|
public virtual void Clear() {}
|
||||||
}
|
|
||||||
|
|
||||||
public static T LoadContent<T>(string name) {
|
public static T LoadContent<T>(string name) {
|
||||||
return MlemGame.LoadContent<T>(name);
|
return MlemGame.LoadContent<T>(name);
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
||||||
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|
|
@ -19,8 +19,7 @@ namespace Demos {
|
||||||
private int current;
|
private int current;
|
||||||
private float progress;
|
private float progress;
|
||||||
|
|
||||||
public EasingsDemo(MlemGame game) : base(game) {
|
public EasingsDemo(MlemGame game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
public override void LoadContent() {
|
public override void LoadContent() {
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
|
|
|
@ -9,6 +9,7 @@ using MLEM.Textures;
|
||||||
using MLEM.Ui;
|
using MLEM.Ui;
|
||||||
using MLEM.Ui.Elements;
|
using MLEM.Ui.Elements;
|
||||||
using MLEM.Ui.Style;
|
using MLEM.Ui.Style;
|
||||||
|
using MonoGame.Framework.Utilities;
|
||||||
|
|
||||||
namespace Demos {
|
namespace Demos {
|
||||||
public class GameImpl : MlemGame {
|
public class GameImpl : MlemGame {
|
||||||
|
@ -45,9 +46,12 @@ namespace Demos {
|
||||||
|
|
||||||
protected override void LoadContent() {
|
protected override void LoadContent() {
|
||||||
// TODO remove with MonoGame 3.8.1 https://github.com/MonoGame/MonoGame/issues/7298
|
// TODO remove with MonoGame 3.8.1 https://github.com/MonoGame/MonoGame/issues/7298
|
||||||
this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280;
|
if (PlatformInfo.MonoGamePlatform == MonoGamePlatform.DesktopGL) {
|
||||||
this.GraphicsDeviceManager.PreferredBackBufferHeight = 720;
|
this.GraphicsDeviceManager.PreferredBackBufferWidth = 1280;
|
||||||
this.GraphicsDeviceManager.ApplyChanges();
|
this.GraphicsDeviceManager.PreferredBackBufferHeight = 720;
|
||||||
|
this.GraphicsDeviceManager.ApplyChanges();
|
||||||
|
}
|
||||||
|
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
this.UiSystem.AutoScaleReferenceSize = new Point(1280, 720);
|
this.UiSystem.AutoScaleReferenceSize = new Point(1280, 720);
|
||||||
this.UiSystem.AutoScaleWithScreen = true;
|
this.UiSystem.AutoScaleWithScreen = true;
|
||||||
|
@ -68,7 +72,7 @@ namespace Demos {
|
||||||
IsHidden = true
|
IsHidden = true
|
||||||
});
|
});
|
||||||
|
|
||||||
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' <c CornflowerBlue><l https://github.com/Ellpeck/MLEM/tree/main/Demos>source code</l></c> for more in-depth explanations of their functionality or the <c CornflowerBlue><l https://mlem.ellpeck.de/>website</l></c> for tutorials and API documentation."));
|
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' <l https://github.com/Ellpeck/MLEM/tree/main/Demos>source code</l> for more in-depth explanations of their functionality or the <l https://mlem.ellpeck.de/>website</l> for tutorials and API documentation."));
|
||||||
selection.AddChild(new VerticalSpace(5));
|
selection.AddChild(new VerticalSpace(5));
|
||||||
foreach (var demo in Demos) {
|
foreach (var demo in Demos) {
|
||||||
selection.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), demo.Key, demo.Value.Item1) {
|
selection.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), demo.Key, demo.Value.Item1) {
|
||||||
|
@ -95,7 +99,8 @@ namespace Demos {
|
||||||
PanelTexture = new NinePatch(new TextureRegion(tex, 0, 8, 24, 24), 8),
|
PanelTexture = new NinePatch(new TextureRegion(tex, 0, 8, 24, 24), 8),
|
||||||
ButtonTexture = new NinePatch(new TextureRegion(tex, 24, 8, 16, 16), 4),
|
ButtonTexture = new NinePatch(new TextureRegion(tex, 24, 8, 16, 16), 4),
|
||||||
ScrollBarBackground = new NinePatch(new TextureRegion(tex, 12, 0, 4, 8), 1, 1, 2, 2),
|
ScrollBarBackground = new NinePatch(new TextureRegion(tex, 12, 0, 4, 8), 1, 1, 2, 2),
|
||||||
ScrollBarScrollerTexture = new NinePatch(new TextureRegion(tex, 8, 0, 4, 8), 1, 1, 2, 2)
|
ScrollBarScrollerTexture = new NinePatch(new TextureRegion(tex, 8, 0, 4, 8), 1, 1, 2, 2),
|
||||||
|
LinkColor = Color.CornflowerBlue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@ namespace Demos {
|
||||||
private List<Point> path;
|
private List<Point> path;
|
||||||
private Button regenerateButton;
|
private Button regenerateButton;
|
||||||
|
|
||||||
public PathfindingDemo(MlemGame game) : base(game) {
|
public PathfindingDemo(MlemGame game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
private async void Init() {
|
private async void Init() {
|
||||||
this.path = null;
|
this.path = null;
|
||||||
|
|
|
@ -23,8 +23,7 @@ namespace Demos {
|
||||||
private NinePatch testPatch;
|
private NinePatch testPatch;
|
||||||
private Panel root;
|
private Panel root;
|
||||||
|
|
||||||
public UiDemo(MlemGame game) : base(game) {
|
public UiDemo(MlemGame game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
public override void LoadContent() {
|
public override void LoadContent() {
|
||||||
this.testTexture = LoadContent<Texture2D>("Textures/Test");
|
this.testTexture = LoadContent<Texture2D>("Textures/Test");
|
||||||
|
@ -48,7 +47,8 @@ namespace Demos {
|
||||||
CheckboxCheckmark = new TextureRegion(this.testTexture, 24, 0, 8, 8),
|
CheckboxCheckmark = new TextureRegion(this.testTexture, 24, 0, 8, 8),
|
||||||
RadioTexture = new NinePatch(new TextureRegion(this.testTexture, 16, 0, 8, 8), 3),
|
RadioTexture = new NinePatch(new TextureRegion(this.testTexture, 16, 0, 8, 8), 3),
|
||||||
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8),
|
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8),
|
||||||
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/MonospacedFont"))}}
|
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/MonospacedFont"))}},
|
||||||
|
LinkColor = Color.CornflowerBlue
|
||||||
};
|
};
|
||||||
var untexturedStyle = new UntexturedStyle(this.SpriteBatch) {
|
var untexturedStyle = new UntexturedStyle(this.SpriteBatch) {
|
||||||
TextScale = style.TextScale,
|
TextScale = style.TextScale,
|
||||||
|
@ -82,7 +82,7 @@ namespace Demos {
|
||||||
this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), "Change Style") {
|
this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), "Change Style") {
|
||||||
OnPressed = element => this.UiSystem.Style = this.UiSystem.Style == untexturedStyle ? style : untexturedStyle,
|
OnPressed = element => this.UiSystem.Style = this.UiSystem.Style == untexturedStyle ? style : untexturedStyle,
|
||||||
PositionOffset = new Vector2(0, 1),
|
PositionOffset = new Vector2(0, 1),
|
||||||
Texture = this.testPatch
|
Style = untexturedStyle
|
||||||
});
|
});
|
||||||
|
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
this.root.AddChild(new VerticalSpace(3));
|
||||||
|
@ -207,8 +207,15 @@ namespace Demos {
|
||||||
|
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
this.root.AddChild(new VerticalSpace(3));
|
||||||
this.root.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Disabled button", "This button can't be clicked or moved to using automatic navigation") {IsDisabled = true}).PositionOffset = new Vector2(0, 1);
|
this.root.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Disabled button", "This button can't be clicked or moved to using automatic navigation") {IsDisabled = true}).PositionOffset = new Vector2(0, 1);
|
||||||
|
this.root.AddChild(new Checkbox(Anchor.AutoLeft, new Vector2(1, 10), "Disabled checkbox") {IsDisabled = true}).PositionOffset = new Vector2(0, 1);
|
||||||
|
this.root.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 10), "Disabled tooltip button", "This button can't be clicked, but can be moved to using automatic navigation, and will display its tooltip even when done so.") {
|
||||||
|
CanSelectDisabled = true,
|
||||||
|
IsDisabled = true,
|
||||||
|
Tooltip = {DisplayInAutoNavMode = true},
|
||||||
|
PositionOffset = new Vector2(0, 1)
|
||||||
|
});
|
||||||
|
|
||||||
const string alignText = "Paragraphs can have <c CornflowerBlue><l Left>left</l></c> aligned text, <c CornflowerBlue><l Right>right</l></c> aligned text and <c CornflowerBlue><l Center>center</l></c> aligned text.";
|
const string alignText = "Paragraphs can have <l Left>left</l> aligned text, <l Right>right</l> aligned text and <l Center>center</l> aligned text.";
|
||||||
this.root.AddChild(new VerticalSpace(3));
|
this.root.AddChild(new VerticalSpace(3));
|
||||||
var alignPar = this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, alignText));
|
var alignPar = this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, alignText));
|
||||||
alignPar.LinkAction = (l, c) => {
|
alignPar.LinkAction = (l, c) => {
|
||||||
|
|
|
@ -22,9 +22,6 @@ protected override void Update(GameTime gameTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Draw(GameTime gameTime) {
|
protected override void Draw(GameTime gameTime) {
|
||||||
// DrawEarly needs to be called before clearing your graphics context
|
|
||||||
this.UiSystem.DrawEarly(gameTime, this.SpriteBatch);
|
|
||||||
|
|
||||||
this.GraphicsDevice.Clear(Color.CornflowerBlue);
|
this.GraphicsDevice.Clear(Color.CornflowerBlue);
|
||||||
// Do your regular game drawing here
|
// Do your regular game drawing here
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
{
|
{
|
||||||
"metadata": [
|
"metadata": [{
|
||||||
{
|
"src": [{
|
||||||
"src": [
|
"src": "../",
|
||||||
{
|
"files": ["**/MLEM**.csproj"]
|
||||||
"src": "../",
|
}],
|
||||||
"files": ["**/MLEM**.csproj"]
|
"dest": "api"
|
||||||
}
|
}],
|
||||||
],
|
|
||||||
"dest": "api"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"build": {
|
"build": {
|
||||||
"content": [
|
"content": [{
|
||||||
{
|
|
||||||
"files": [
|
"files": [
|
||||||
"articles/**.md",
|
"articles/**.md",
|
||||||
"articles/**/toc.yml",
|
"articles/**/toc.yml",
|
||||||
|
@ -28,8 +23,7 @@
|
||||||
"src": ".."
|
"src": ".."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resource": [
|
"resource": [{
|
||||||
{
|
|
||||||
"files": [
|
"files": [
|
||||||
"favicon.ico"
|
"favicon.ico"
|
||||||
]
|
]
|
||||||
|
@ -42,7 +36,7 @@
|
||||||
"globalMetadata": {
|
"globalMetadata": {
|
||||||
"_appTitle": "MLEM Documentation",
|
"_appTitle": "MLEM Documentation",
|
||||||
"_appLogoPath": "Logo.svg",
|
"_appLogoPath": "Logo.svg",
|
||||||
"_appFooter": "<a href=\"https://github.com/Ellpeck/MLEM\">© 2019-2021 Ellpeck</a> – <a href=\"https://ellpeck.de/impressum\">Impressum</a> – <a href=\"https://ellpeck.de/privacy\">Privacy</a>",
|
"_appFooter": "<a href=\"https://github.com/Ellpeck/MLEM\">© 2019-2021 Ellpeck</a> – <a href=\"https://ellpeck.de/impressum\">Impressum</a> – <a href=\"https://ellpeck.de/privacy\">Privacy</a> – <a href=\"https://status.ellpeck.de\">Status</a>",
|
||||||
"_enableSearch": true
|
"_enableSearch": true
|
||||||
},
|
},
|
||||||
"dest": "_site",
|
"dest": "_site",
|
||||||
|
@ -50,7 +44,8 @@
|
||||||
"fileMetadataFiles": [],
|
"fileMetadataFiles": [],
|
||||||
"template": [
|
"template": [
|
||||||
"default",
|
"default",
|
||||||
"template"
|
"templates/darkfx",
|
||||||
|
"templates/custom"
|
||||||
],
|
],
|
||||||
"postProcessors": [],
|
"postProcessors": [],
|
||||||
"markdownEngineName": "markdig",
|
"markdownEngineName": "markdig",
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
- **MLEM** is the base package, which provides extension methods and additional features for MonoGame
|
- **MLEM** is the base package, which provides extension methods and additional features for MonoGame
|
||||||
- **MLEM.Ui** features a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
|
- **MLEM.Ui** features a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
|
||||||
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame libraries
|
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame libraries
|
||||||
- **MLEM.Data** provides simple data handling
|
- **MLEM.Data** provides simple loading and processing of textures and data
|
||||||
- **MLEM.Startup** combines MLEM with some other useful libraries into a quick Game startup class
|
- **MLEM.Startup** combines MLEM with some other useful libraries into a quick Game startup class
|
||||||
- **MLEM.Templates** contains cross-platform project templates
|
- **MLEM.Templates** contains cross-platform project templates
|
||||||
|
|
||||||
# Made with MLEM
|
# Made with MLEM
|
||||||
- [A Breath of Spring Air](https://ellpeck.itch.io/a-breath-of-spring-air), a short platformer ([Source](https://git.ellpeck.de/Ellpeck/GreatSpringGameJam))
|
- [A Breath of Spring Air](https://ellpeck.itch.io/a-breath-of-spring-air), a short platformer ([Source](https://git.ellpeck.de/Ellpeck/GreatSpringGameJam))
|
||||||
- [Don't Wake Up](https://ellpeck.itch.io/dont-wake-up), a short puzzle game ([Source](https://github.com/Ellpeck/DontLetGo))
|
- [Don't Wake Up](https://ellpeck.itch.io/dont-wake-up), a short puzzle game ([Source](https://github.com/Ellpeck/DontLetGo))
|
||||||
|
- [Pong clone](https://github.com/luanfagu/pong), a very simple pong clone ([Source](https://github.com/luanfagu/pong))
|
||||||
- [Tiny Life](https://tinylifegame.com), an isometric life simulation game ([Modding API](https://github.com/Ellpeck/TinyLifeExampleMod))
|
- [Tiny Life](https://tinylifegame.com), an isometric life simulation game ([Modding API](https://github.com/Ellpeck/TinyLifeExampleMod))
|
||||||
|
|
||||||
If you created a game with the help of MLEM, you can get it added to this list by submitting it on the [issue tracker](https://github.com/Ellpeck/MLEM/issues). If its source is public, other people will be able to use your project as an example, too!
|
If you created a game with the help of MLEM, you can get it added to this list by submitting it on the [issue tracker](https://github.com/Ellpeck/MLEM/issues). If its source is public, other people will be able to use your project as an example, too!
|
||||||
|
@ -37,8 +38,9 @@ MLEM's [text formatting system](https://mlem.ellpeck.de/articles/text_formatting
|
||||||
![An image showing text with various colors and other formatting](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Formatting.png)
|
![An image showing text with various colors and other formatting](https://raw.githubusercontent.com/Ellpeck/MLEM/release/Media/Formatting.png)
|
||||||
|
|
||||||
# Friends of MLEM
|
# Friends of MLEM
|
||||||
There are several other NuGet packages and tools that work well in combination with MonoGame and MLEM. Here are some of them:
|
There are several other libraries and tools that work well in combination with MonoGame and MLEM. Here are some of them:
|
||||||
- [Contentless](https://github.com/Ellpeck/Contentless), a tool that removes the need to add assets to the MonoGame Content Pipeline manually
|
- [Contentless](https://github.com/Ellpeck/Contentless), a tool that removes the need to add assets to the MonoGame Content Pipeline manually
|
||||||
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET Core applications into several distributable formats
|
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET Core applications into several distributable formats
|
||||||
- [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended), a package that also provides several additional features for MonoGame
|
- [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended), a package that also provides several additional features for MonoGame
|
||||||
- [Coroutine](https://github.com/Ellpeck/Coroutine), a package that implements Unity-style coroutines for any project
|
- [Coroutine](https://github.com/Ellpeck/Coroutine), a package that implements Unity-style coroutines for any project
|
||||||
|
- [Illumilib](https://github.com/Ellpeck/Illumilib), a simple keyboard and mouse lighting library with support for Razer, Logitech and Corsair devices
|
||||||
|
|
40
Docs/templates/darkfx/partials/affix.tmpl.partial
Normal file
40
Docs/templates/darkfx/partials/affix.tmpl.partial
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||||
|
|
||||||
|
<div class="hidden-sm col-md-2" role="complementary">
|
||||||
|
<div class="sideaffix">
|
||||||
|
{{^_disableContribution}}
|
||||||
|
<div class="contribution">
|
||||||
|
<ul class="nav">
|
||||||
|
{{#docurl}}
|
||||||
|
<li>
|
||||||
|
<a href="{{docurl}}" class="contribution-link">{{__global.improveThisDoc}}</a>
|
||||||
|
</li>
|
||||||
|
{{/docurl}}
|
||||||
|
{{#sourceurl}}
|
||||||
|
<li>
|
||||||
|
<a href="{{sourceurl}}" class="contribution-link">{{__global.viewSource}}</a>
|
||||||
|
</li>
|
||||||
|
{{/sourceurl}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/_disableContribution}}
|
||||||
|
<div class="toggle-mode">
|
||||||
|
<div class="icon">
|
||||||
|
<i aria-hidden="true">☀</i>
|
||||||
|
</div>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="switch-style">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
<div class="icon">
|
||||||
|
<i aria-hidden="true">☾</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
|
||||||
|
<h5>{{__global.inThisArticle}}</h5>
|
||||||
|
<div></div>
|
||||||
|
<!-- <p><a class="back-to-top" href="#top">Back to top</a><p> -->
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
29
Docs/templates/darkfx/partials/footer.tmpl.partial
Normal file
29
Docs/templates/darkfx/partials/footer.tmpl.partial
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="grad-bottom"></div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<span class="pull-right">
|
||||||
|
<a href="#top">Back to top</a>
|
||||||
|
</span>
|
||||||
|
<div class="pull-left">
|
||||||
|
{{{_appFooter}}}
|
||||||
|
{{^_appFooter}}<span>Generated by <strong>DocFX</strong></span>{{/_appFooter}}
|
||||||
|
</div>
|
||||||
|
<div class="toggle-mode pull-right visible-sm visible-xs">
|
||||||
|
<div class="icon">
|
||||||
|
<i aria-hidden="true">☀</i>
|
||||||
|
</div>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="switch-style-m">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
<div class="icon">
|
||||||
|
<i aria-hidden="true">☾</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="{{_rel}}styles/toggle-theme.js"></script>
|
||||||
|
</footer>
|
20
Docs/templates/darkfx/partials/head.tmpl.partial
Normal file
20
Docs/templates/darkfx/partials/head.tmpl.partial
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{{!Copyright (c) Oscar Vasquez. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||||
|
<meta name="generator" content="docfx {{_docfxVersion}}">
|
||||||
|
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||||
|
<link rel="shortcut icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
|
||||||
|
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
|
||||||
|
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
|
||||||
|
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
||||||
|
<meta property="docfx:navrel" content="{{_navRel}}">
|
||||||
|
<meta property="docfx:tocrel" content="{{_tocRel}}">
|
||||||
|
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
|
||||||
|
{{#_enableSearch}}<meta property="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
|
||||||
|
{{#_enableNewTab}}<meta property="docfx:newtab" content="true">{{/_enableNewTab}}
|
||||||
|
</head>
|
470
Docs/templates/darkfx/styles/main.css
Normal file
470
Docs/templates/darkfx/styles/main.css
Normal file
|
@ -0,0 +1,470 @@
|
||||||
|
:root, body.dark-theme {
|
||||||
|
--color-foreground: #ccd5dc;
|
||||||
|
--color-navbar: #66666d;
|
||||||
|
--color-breadcrumb: #999;
|
||||||
|
--color-underline: #ddd;
|
||||||
|
--color-toc-hover: #fff;
|
||||||
|
--color-background: #2d2d30;
|
||||||
|
--color-background-subnav: #333337;
|
||||||
|
--color-background-dark: #1e1e1e;
|
||||||
|
--color-background-table-alt: #212123;
|
||||||
|
--color-background-quote: #69696e;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.light-theme {
|
||||||
|
--color-foreground: #171717;
|
||||||
|
--color-breadcrumb: #4a4a4a;
|
||||||
|
--color-toc-hover: #4c4c4c;
|
||||||
|
--color-background: #ffffff;
|
||||||
|
--color-background-subnav: #f5f5f5;
|
||||||
|
--color-background-dark: #ddd;
|
||||||
|
--color-background-table-alt: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 14px;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.focus, .btn:focus, .btn:hover {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h1, article h2, article h3, article h4 {
|
||||||
|
margin-top: 35px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h4 {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--color-underline);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand>img {
|
||||||
|
color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subnav {
|
||||||
|
border-top: 1px solid var(--color-underline);
|
||||||
|
background-color: var(--color-background-subnav);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav, .fixed_header, .toc {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse {
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text {
|
||||||
|
color: var(--color-navbar);
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-nav>li>a:focus, .navbar-inverse .navbar-nav>li>a:hover {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
border-bottom: 3px solid var(--color-background-subnav);
|
||||||
|
transition: all ease 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-nav>.active>a, .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
border-bottom: 3px solid var(--color-foreground);
|
||||||
|
transition: all ease 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-form .form-control {
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-theme .navbar-brand svg {
|
||||||
|
filter: brightness(20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .level1>li {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .nav>li>a {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidefilter {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidefilter {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-filter {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-filter>input {
|
||||||
|
border: none;
|
||||||
|
border-radius: unset;
|
||||||
|
background-color: var(--color-background-subnav);
|
||||||
|
padding: 5px 0 5px 20px;
|
||||||
|
font-size: 90%
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-filter>.clear-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 17px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-filter>input:focus {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
transition: all ease 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-filter>.filter-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidetoc>.toc {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidetoc {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
background-color: inherit;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert>p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert>h5 {
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 2px solid;
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
border-radius: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert>ul {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 5px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-info {
|
||||||
|
color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-warning {
|
||||||
|
color: #f57f17;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-danger {
|
||||||
|
color: #d32f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 9.5px;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: var(--color-background-dark) !important;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .nav>li.active>.expand-stub::before, .toc .nav>li.in>.expand-stub::before, .toc .nav>li.in.active>.expand-stub::before, .toc .nav>li.filtered>.expand-stub::before {
|
||||||
|
content: "▾";
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .nav>li>.expand-stub::before, .toc .nav>li.active>.expand-stub::before {
|
||||||
|
content: "▸";
|
||||||
|
}
|
||||||
|
|
||||||
|
.affix ul ul>li>a:before {
|
||||||
|
content: "|";
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
background-color: var(--color-background-subnav);
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb .label.label-primary {
|
||||||
|
background: #444;
|
||||||
|
border-radius: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#breadcrumb .breadcrumb>li a {
|
||||||
|
border-radius: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 85%;
|
||||||
|
display: inline;
|
||||||
|
padding: 0 .6em 0;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: baseline;
|
||||||
|
color: var(--color-breadcrumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#breadcrumb .breadcrumb>li a:hover {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
transition: all ease 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb>li+li:before {
|
||||||
|
content: "⯈";
|
||||||
|
font-size: 75%;
|
||||||
|
color: var(--color-background-dark);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-theme .breadcrumb>li+li:before {
|
||||||
|
color: var(--color-foreground)
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .level1>li {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 130%;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
border-top: none;
|
||||||
|
background-color: var(--color-background-dark);
|
||||||
|
padding: 15px 0;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc .nav>li>a:hover, .toc .nav>li>a:focus {
|
||||||
|
color: var(--color-toc-hover);
|
||||||
|
transition: all ease 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
background-color: var(--color-background-subnav);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: #66afe9;
|
||||||
|
outline: 0;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#search-query:focus {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-bordered, .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
|
||||||
|
border: 1px solid var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||||
|
background-color: var(--color-background-table-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 110%;
|
||||||
|
border-left: 5px solid var(--color-background-quote);
|
||||||
|
color: var(--color-background-quote);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {
|
||||||
|
background-color: var(--color-background-subnav);
|
||||||
|
border-color: var(--color-background-subnav);
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb>li, .pagination {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabGroup a[role="tab"] {
|
||||||
|
border-bottom: 2px solid var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabGroup a[role="tab"][aria-selected="true"] {
|
||||||
|
color: var(--color-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabGroup section[role="tabpanel"] {
|
||||||
|
border: 1px solid var(--color-background-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideaffix > div.contribution > ul > li > a.contribution-link:hover {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 3px;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: #337ab7;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + .slider {
|
||||||
|
box-shadow: 0 0 1px #337ab7;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
-webkit-transform: translateX(19px);
|
||||||
|
-ms-transform: translateX(19px);
|
||||||
|
transform: translateX(19px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rounded sliders */
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.toggle-mode .icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-mode .icon i {
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 17px;
|
||||||
|
display: inline-block;
|
||||||
|
padding-right: 7px;
|
||||||
|
padding-left: 7px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1600px) {
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.sidefilter {
|
||||||
|
width: 18%;
|
||||||
|
}
|
||||||
|
.sidetoc {
|
||||||
|
width: 18%;
|
||||||
|
}
|
||||||
|
.article.grid-right {
|
||||||
|
margin-left: 19%;
|
||||||
|
}
|
||||||
|
.sideaffix {
|
||||||
|
width: 11.5%;
|
||||||
|
}
|
||||||
|
.affix ul>li.active>a {
|
||||||
|
white-space: initial;
|
||||||
|
}
|
||||||
|
.affix ul>li>a {
|
||||||
|
width: 99%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
35
Docs/templates/darkfx/styles/toggle-theme.js
Normal file
35
Docs/templates/darkfx/styles/toggle-theme.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const sw = document.getElementById("switch-style"), sw_mobile = document.getElementById("switch-style-m"), b = document.body;
|
||||||
|
if (b) {
|
||||||
|
function toggleTheme(target, dark) {
|
||||||
|
target.classList.toggle("dark-theme", dark)
|
||||||
|
target.classList.toggle("light-theme", !dark)
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchEventListener() {
|
||||||
|
toggleTheme(b, this.checked);
|
||||||
|
if (window.localStorage) {
|
||||||
|
this.checked ? localStorage.setItem("theme", "dark-theme") : localStorage.setItem("theme", "light-theme")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDarkTheme = !window.localStorage || !window.localStorage.getItem("theme") || window.localStorage && localStorage.getItem("theme") === "dark-theme";
|
||||||
|
|
||||||
|
if(sw && sw_mobile){
|
||||||
|
sw.checked = isDarkTheme;
|
||||||
|
sw_mobile.checked = isDarkTheme;
|
||||||
|
|
||||||
|
sw.addEventListener("change", switchEventListener);
|
||||||
|
sw_mobile.addEventListener("change", switchEventListener);
|
||||||
|
|
||||||
|
// sync state between switches
|
||||||
|
sw.addEventListener("change", function() {
|
||||||
|
sw_mobile.checked = this.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
sw_mobile.addEventListener("change", function() {
|
||||||
|
sw.checked = this.checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTheme(b, isDarkTheme);
|
||||||
|
}
|
|
@ -76,8 +76,7 @@ namespace MLEM.Data.Content {
|
||||||
r.Name = assetName;
|
r.Name = assetName;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException) {
|
} catch (FileNotFoundException) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new ContentLoadException($"Asset {assetName} not found. Tried files {string.Join(", ", triedFiles)}");
|
throw new ContentLoadException($"Asset {assetName} not found. Tried files {string.Join(", ", triedFiles)}");
|
||||||
|
@ -96,11 +95,11 @@ namespace MLEM.Data.Content {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the component. Used to load non-graphical resources.
|
/// Initializes the component. Used to load non-graphical resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize() {
|
public void Initialize() {}
|
||||||
}
|
|
||||||
|
|
||||||
private static List<RawContentReader> CollectContentReaders() {
|
private static List<RawContentReader> CollectContentReaders() {
|
||||||
var ret = new List<RawContentReader>();
|
var ret = new List<RawContentReader>();
|
||||||
|
var assemblyExceptions = new List<Exception>();
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
|
||||||
try {
|
try {
|
||||||
if (assembly.IsDynamic)
|
if (assembly.IsDynamic)
|
||||||
|
@ -116,10 +115,12 @@ namespace MLEM.Data.Content {
|
||||||
throw new NotSupportedException($"The type {type} cannot be constructed by a RawContentManager. Does it have a visible parameterless constructor?", e);
|
throw new NotSupportedException($"The type {type} cannot be constructed by a RawContentManager. Does it have a visible parameterless constructor?", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (Exception e) {
|
||||||
// ignored
|
assemblyExceptions.Add(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret.Count <= 0)
|
||||||
|
throw new AggregateException("Failed to construct any RawContentReader instances", assemblyExceptions);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,7 @@ namespace MLEM.Data {
|
||||||
using (var reader = new JsonTextReader(stream))
|
using (var reader = new JsonTextReader(stream))
|
||||||
return serializerToUse.Deserialize<T>(reader);
|
return serializerToUse.Deserialize<T>(reader);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException) {
|
} catch (FileNotFoundException) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new ContentLoadException($"Asset {name} not found. Tried files {string.Join(", ", triedFiles)}");
|
throw new ContentLoadException($"Asset {name} not found. Tried files {string.Join(", ", triedFiles)}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace MLEM.Data {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A set of extensions for dealing with copying objects.
|
/// A set of extensions for dealing with copying objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public static class CopyExtensions {
|
public static class CopyExtensions {
|
||||||
|
|
||||||
private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
|
@ -21,6 +22,7 @@ namespace MLEM.Data {
|
||||||
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
||||||
/// <typeparam name="T">The type of the object to copy</typeparam>
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
/// <returns>A shallow copy of the object</returns>
|
/// <returns>A shallow copy of the object</returns>
|
||||||
|
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public static T Copy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
public static T Copy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
||||||
var copy = (T) Construct(typeof(T), flags);
|
var copy = (T) Construct(typeof(T), flags);
|
||||||
obj.CopyInto(copy, flags, fieldInclusion);
|
obj.CopyInto(copy, flags, fieldInclusion);
|
||||||
|
@ -36,6 +38,7 @@ namespace MLEM.Data {
|
||||||
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
||||||
/// <typeparam name="T">The type of the object to copy</typeparam>
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
/// <returns>A deep copy of the object</returns>
|
/// <returns>A deep copy of the object</returns>
|
||||||
|
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public static T DeepCopy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
public static T DeepCopy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
||||||
var copy = (T) Construct(typeof(T), flags);
|
var copy = (T) Construct(typeof(T), flags);
|
||||||
obj.DeepCopyInto(copy, flags, fieldInclusion);
|
obj.DeepCopyInto(copy, flags, fieldInclusion);
|
||||||
|
@ -50,6 +53,7 @@ namespace MLEM.Data {
|
||||||
/// <param name="flags">The binding flags for field searching</param>
|
/// <param name="flags">The binding flags for field searching</param>
|
||||||
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
||||||
/// <typeparam name="T">The type of the object to copy</typeparam>
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
|
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
||||||
foreach (var field in typeof(T).GetFields(flags)) {
|
foreach (var field in typeof(T).GetFields(flags)) {
|
||||||
if (fieldInclusion == null || fieldInclusion(field))
|
if (fieldInclusion == null || fieldInclusion(field))
|
||||||
|
@ -66,6 +70,7 @@ namespace MLEM.Data {
|
||||||
/// <param name="flags">The binding flags for field searching</param>
|
/// <param name="flags">The binding flags for field searching</param>
|
||||||
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
|
||||||
/// <typeparam name="T">The type of the object to copy</typeparam>
|
/// <typeparam name="T">The type of the object to copy</typeparam>
|
||||||
|
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
|
||||||
foreach (var field in obj.GetType().GetFields(flags)) {
|
foreach (var field in obj.GetType().GetFields(flags)) {
|
||||||
if (fieldInclusion != null && !fieldInclusion(field))
|
if (fieldInclusion != null && !fieldInclusion(field))
|
||||||
|
@ -109,8 +114,6 @@ namespace MLEM.Data {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An attribute that, when added to a constructor, will make that constructor the one used by <see cref="CopyExtensions.Copy{T}"/>, <see cref="CopyExtensions.DeepCopy{T}"/> and <see cref="CopyExtensions.DeepCopyInto{T}"/>.
|
/// An attribute that, when added to a constructor, will make that constructor the one used by <see cref="CopyExtensions.Copy{T}"/>, <see cref="CopyExtensions.DeepCopy{T}"/> and <see cref="CopyExtensions.DeepCopyInto{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Constructor)]
|
[AttributeUsage(AttributeTargets.Constructor), Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
|
||||||
public class CopyConstructorAttribute : Attribute {
|
public class CopyConstructorAttribute : Attribute {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -29,9 +29,7 @@ namespace MLEM.Data.Json {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type that the dictionary is declared in</param>
|
/// <param name="type">The type that the dictionary is declared in</param>
|
||||||
/// <param name="memberName">The name of the dictionary itself</param>
|
/// <param name="memberName">The name of the dictionary itself</param>
|
||||||
public StaticJsonConverter(Type type, string memberName) :
|
public StaticJsonConverter(Type type, string memberName) : this(GetEntries(type, memberName)) {}
|
||||||
this(GetEntries(type, memberName)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Writes the JSON representation of the object.</summary>
|
/// <summary>Writes the JSON representation of the object.</summary>
|
||||||
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
|
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Ellpeck</Authors>
|
<Authors>Ellpeck</Authors>
|
||||||
<Description>Simple data handling for MLEM Library for Extending MonoGame</Description>
|
<Description>Simple loading and processing of textures and data for MLEM Library for Extending MonoGame</Description>
|
||||||
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
|
<PackageReleaseNotes>See the full changelog at https://mlem.ellpeck.de/CHANGELOG</PackageReleaseNotes>
|
||||||
<PackageTags>monogame ellpeck mlem utility extensions data serialize</PackageTags>
|
<PackageTags>monogame ellpeck mlem utility extensions data serialize</PackageTags>
|
||||||
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
|
<PackageProjectUrl>https://mlem.ellpeck.de/</PackageProjectUrl>
|
||||||
|
@ -17,15 +17,17 @@
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<NoWarn>NU1701</NoWarn>
|
<NoWarn>NU1701</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
|
|
||||||
<!--TODO remove lidgren support eventually (methods marked as obsolete since 5.2.0)-->
|
<!--TODO remove lidgren support eventually (methods marked as obsolete since 5.2.0)-->
|
||||||
<PackageReference Include="Lidgren.Network" Version="1.0.2">
|
<PackageReference Include="Lidgren.Network" Version="1.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2">
|
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -33,7 +35,7 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace MLEM.Extended.Extensions {
|
||||||
/// <param name="region">The nine patch to convert</param>
|
/// <param name="region">The nine patch to convert</param>
|
||||||
/// <returns>The converted nine patch</returns>
|
/// <returns>The converted nine patch</returns>
|
||||||
public static TextureRegion2D ToExtended(this TextureRegion region) {
|
public static TextureRegion2D ToExtended(this TextureRegion region) {
|
||||||
return new TextureRegion2D(region.Texture, region.U, region.V, region.Width, region.Height);
|
return new TextureRegion2D(region.Name, region.Texture, region.U, region.V, region.Width, region.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -32,7 +32,7 @@ namespace MLEM.Extended.Extensions {
|
||||||
/// <param name="patch">The nine patch to convert</param>
|
/// <param name="patch">The nine patch to convert</param>
|
||||||
/// <returns>The converted nine patch</returns>
|
/// <returns>The converted nine patch</returns>
|
||||||
public static NinePatch ToMlem(this NinePatchRegion2D patch) {
|
public static NinePatch ToMlem(this NinePatchRegion2D patch) {
|
||||||
return new NinePatch(new TextureRegion(patch.Texture, patch.Bounds), patch.LeftPadding, patch.RightPadding, patch.TopPadding, patch.BottomPadding);
|
return new NinePatch(((TextureRegion2D) patch).ToMlem(), patch.LeftPadding, patch.RightPadding, patch.TopPadding, patch.BottomPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -41,7 +41,7 @@ namespace MLEM.Extended.Extensions {
|
||||||
/// <param name="region">The nine patch to convert</param>
|
/// <param name="region">The nine patch to convert</param>
|
||||||
/// <returns>The converted nine patch</returns>
|
/// <returns>The converted nine patch</returns>
|
||||||
public static TextureRegion ToMlem(this TextureRegion2D region) {
|
public static TextureRegion ToMlem(this TextureRegion2D region) {
|
||||||
return new TextureRegion(region.Texture, region.Bounds);
|
return new TextureRegion(region.Texture, region.Bounds) {Name = region.Name};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Font;
|
using MLEM.Font;
|
||||||
|
@ -38,14 +37,9 @@ namespace MLEM.Extended.Font {
|
||||||
return region != null ? new Vector2(region.XAdvance, region.Height).X : 0;
|
return region != null ? new Vector2(region.XAdvance, region.Height).X : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc />
|
||||||
public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
protected override void DrawChar(SpriteBatch batch, string cString, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth);
|
batch.DrawString(this.Font, cString, position, color, rotation, Vector2.Zero, scale, effects, layerDepth);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
|
||||||
batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Text;
|
|
||||||
using FontStashSharp;
|
using FontStashSharp;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
@ -33,20 +32,15 @@ namespace MLEM.Extended.Font {
|
||||||
this.Italic = italic != null ? new GenericStashFont(italic) : this;
|
this.Italic = italic != null ? new GenericStashFont(italic) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
|
||||||
this.Font.DrawText(batch, text, position, color, scale, rotation, origin, layerDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
|
||||||
this.Font.DrawText(batch, text, position, color, scale, rotation, origin, layerDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override float MeasureChar(char c) {
|
protected override float MeasureChar(char c) {
|
||||||
return this.Font.MeasureString(c.ToCachedString()).X;
|
return this.Font.MeasureString(c.ToCachedString()).X;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void DrawChar(SpriteBatch batch, string cString, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
|
this.Font.DrawText(batch, cString, position, color, scale, rotation, Vector2.Zero, layerDepth);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Ellpeck</Authors>
|
<Authors>Ellpeck</Authors>
|
||||||
<Description>MLEM Library for Extending MonoGame extension that ties in with MonoGame.Extended and other MonoGame libraries</Description>
|
<Description>MLEM Library for Extending MonoGame extension that ties in with MonoGame.Extended and other MonoGame libraries</Description>
|
||||||
|
@ -16,10 +16,10 @@
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
|
|
||||||
<PackageReference Include="MonoGame.Extended" Version="3.8.0">
|
<PackageReference Include="MonoGame.Extended" Version="3.8.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Ellpeck</Authors>
|
<Authors>Ellpeck</Authors>
|
||||||
<Description>MLEM Library for Extending MonoGame combined with some other useful libraries into a quick Game startup class</Description>
|
<Description>MLEM Library for Extending MonoGame combined with some other useful libraries into a quick Game startup class</Description>
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Coroutine" Version="2.1.3" />
|
<PackageReference Include="Coroutine" Version="2.1.3" />
|
||||||
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
|
|
|
@ -114,7 +114,9 @@ namespace MLEM.Startup {
|
||||||
this.PreDraw?.Invoke(this, gameTime);
|
this.PreDraw?.Invoke(this, gameTime);
|
||||||
CoroutineHandler.RaiseEvent(CoroutineEvents.PreDraw);
|
CoroutineHandler.RaiseEvent(CoroutineEvents.PreDraw);
|
||||||
|
|
||||||
|
#pragma warning disable CS0618
|
||||||
this.UiSystem.DrawEarly(gameTime, this.SpriteBatch);
|
this.UiSystem.DrawEarly(gameTime, this.SpriteBatch);
|
||||||
|
#pragma warning restore CS0618
|
||||||
this.DoDraw(gameTime);
|
this.DoDraw(gameTime);
|
||||||
this.UiSystem.Draw(gameTime, this.SpriteBatch);
|
this.UiSystem.Draw(gameTime, this.SpriteBatch);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<IncludeContentInPack>true</IncludeContentInPack>
|
<IncludeContentInPack>true</IncludeContentInPack>
|
||||||
|
@ -21,11 +21,11 @@
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="content\**\*" Exclude="content\**\.DS_Store;content\**\bin;content\**\obj" />
|
<Content Include="content\**\*" Exclude="content\**\.DS_Store;content\**\bin;content\**\obj" />
|
||||||
<Compile Remove="**\*" />
|
<Compile Remove="**\*" />
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath=""/>
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
@ -7,14 +7,14 @@
|
||||||
<TieredCompilation>false</TieredCompilation>
|
<TieredCompilation>false</TieredCompilation>
|
||||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Contentless" Version="3.0.6" />
|
<PackageReference Include="Contentless" Version="3.*" />
|
||||||
<PackageReference Include="MLEM.Startup" Version="5.1.0" />
|
<PackageReference Include="MLEM.Startup" Version="5.*" />
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
|
||||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MonoGameContentReference Include="Content\Content.mgcb" />
|
<MonoGameContentReference Include="Content\Content.mgcb" />
|
||||||
<Content Include="Content\*\**" />
|
<Content Include="Content\*\**" />
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MLEM.Startup" Version="5.1.0" />
|
<PackageReference Include="MLEM.Startup" Version="5.*" />
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -51,14 +51,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// Set this property to true to mark the button as disabled.
|
/// Set this property to true to mark the button as disabled.
|
||||||
/// A disabled button cannot be moused over, selected or pressed.
|
/// A disabled button cannot be moused over, selected or pressed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDisabled {
|
public virtual bool IsDisabled { get; set; }
|
||||||
get => this.isDisabled;
|
|
||||||
set {
|
|
||||||
this.isDisabled = value;
|
|
||||||
this.CanBePressed = !value;
|
|
||||||
this.CanBeSelected = !value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this button's <see cref="Text"/> should be truncated if it exceeds this button's width.
|
/// Whether this button's <see cref="Text"/> should be truncated if it exceeds this button's width.
|
||||||
/// Defaults to false.
|
/// Defaults to false.
|
||||||
|
@ -70,8 +63,16 @@ namespace MLEM.Ui.Elements {
|
||||||
this.Text.TruncateIfLong = value;
|
this.Text.TruncateIfLong = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this button should be able to be selected even if it <see cref="IsDisabled"/>.
|
||||||
|
/// If this is true, <see cref="CanBeSelected"/> will be able to return true even if <see cref="IsDisabled"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanSelectDisabled;
|
||||||
|
|
||||||
private bool isDisabled;
|
/// <inheritdoc />
|
||||||
|
public override bool CanBeSelected => base.CanBeSelected && (this.CanSelectDisabled || !this.IsDisabled);
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanBePressed => base.CanBePressed && !this.IsDisabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new button with the given settings
|
/// Creates a new button with the given settings
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MLEM.Ui.Elements {
|
||||||
public class Checkbox : Element {
|
public class Checkbox : Element {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The texture that this checkbox uses for drawing
|
/// The texture that this checkbox uses for drawing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StyleProp<NinePatch> Texture;
|
public StyleProp<NinePatch> Texture;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -26,6 +26,15 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StyleProp<Color> HoveredColor;
|
public StyleProp<Color> HoveredColor;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The texture that the checkbox uses when it <see cref="IsDisabled"/>.
|
||||||
|
/// If this is null, it uses its default <see cref="Texture"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StyleProp<NinePatch> DisabledTexture;
|
||||||
|
/// <summary>
|
||||||
|
/// The color that the checkbox uses for drawing when it <see cref="IsDisabled"/>.
|
||||||
|
/// </summary>
|
||||||
|
public StyleProp<Color> DisabledColor;
|
||||||
|
/// <summary>
|
||||||
/// The texture that is rendered on top of this checkbox when it is <see cref="Checked"/>.
|
/// The texture that is rendered on top of this checkbox when it is <see cref="Checked"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StyleProp<TextureRegion> Checkmark;
|
public StyleProp<TextureRegion> Checkmark;
|
||||||
|
@ -41,20 +50,35 @@ namespace MLEM.Ui.Elements {
|
||||||
/// Whether or not this checkbox is currently checked.
|
/// Whether or not this checkbox is currently checked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Checked {
|
public bool Checked {
|
||||||
get => this.checced;
|
get => this.isChecked;
|
||||||
set {
|
set {
|
||||||
if (this.checced != value) {
|
if (this.isChecked != value) {
|
||||||
this.checced = value;
|
this.isChecked = value;
|
||||||
this.OnCheckStateChange?.Invoke(this, this.checced);
|
this.OnCheckStateChange?.Invoke(this, this.isChecked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Set this property to true to mark the checkbox as disabled.
|
||||||
|
/// A disabled checkbox cannot be moused over, selected or toggled.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsDisabled { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// An event that is invoked when this checkbox's <see cref="Checked"/> property changes
|
/// An event that is invoked when this checkbox's <see cref="Checked"/> property changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CheckStateChange OnCheckStateChange;
|
public CheckStateChange OnCheckStateChange;
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this checkbox should be able to be selected even if it <see cref="IsDisabled"/>.
|
||||||
|
/// If this is true, <see cref="CanBeSelected"/> will be able to return true even if <see cref="IsDisabled"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanSelectDisabled;
|
||||||
|
|
||||||
private bool checced;
|
/// <inheritdoc />
|
||||||
|
public override bool CanBeSelected => base.CanBeSelected && (this.CanSelectDisabled || !this.IsDisabled);
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanBePressed => base.CanBePressed && !this.IsDisabled;
|
||||||
|
|
||||||
|
private bool isChecked;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new checkbox with the given settings
|
/// Creates a new checkbox with the given settings
|
||||||
|
@ -64,7 +88,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <param name="label">The checkbox's label text</param>
|
/// <param name="label">The checkbox's label text</param>
|
||||||
/// <param name="defaultChecked">The default value of <see cref="Checked"/></param>
|
/// <param name="defaultChecked">The default value of <see cref="Checked"/></param>
|
||||||
public Checkbox(Anchor anchor, Vector2 size, string label, bool defaultChecked = false) : base(anchor, size) {
|
public Checkbox(Anchor anchor, Vector2 size, string label, bool defaultChecked = false) : base(anchor, size) {
|
||||||
this.checced = defaultChecked;
|
this.isChecked = defaultChecked;
|
||||||
this.OnPressed += element => this.Checked = !this.Checked;
|
this.OnPressed += element => this.Checked = !this.Checked;
|
||||||
|
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
|
@ -87,7 +111,10 @@ namespace MLEM.Ui.Elements {
|
||||||
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
||||||
var tex = this.Texture;
|
var tex = this.Texture;
|
||||||
var color = Color.White * alpha;
|
var color = Color.White * alpha;
|
||||||
if (this.IsMouseOver) {
|
if (this.IsDisabled) {
|
||||||
|
tex = this.DisabledTexture.OrDefault(tex);
|
||||||
|
color = (Color) this.DisabledColor * alpha;
|
||||||
|
} else if (this.IsMouseOver) {
|
||||||
tex = this.HoveredTexture.OrDefault(tex);
|
tex = this.HoveredTexture.OrDefault(tex);
|
||||||
color = (Color) this.HoveredColor * alpha;
|
color = (Color) this.HoveredColor * alpha;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +132,8 @@ namespace MLEM.Ui.Elements {
|
||||||
this.Texture = this.Texture.OrStyle(style.CheckboxTexture);
|
this.Texture = this.Texture.OrStyle(style.CheckboxTexture);
|
||||||
this.HoveredTexture = this.HoveredTexture.OrStyle(style.CheckboxHoveredTexture);
|
this.HoveredTexture = this.HoveredTexture.OrStyle(style.CheckboxHoveredTexture);
|
||||||
this.HoveredColor = this.HoveredColor.OrStyle(style.CheckboxHoveredColor);
|
this.HoveredColor = this.HoveredColor.OrStyle(style.CheckboxHoveredColor);
|
||||||
|
this.DisabledTexture = this.DisabledTexture.OrStyle(style.CheckboxDisabledTexture);
|
||||||
|
this.DisabledColor = this.DisabledColor.OrStyle(style.CheckboxDisabledColor);
|
||||||
this.Checkmark = this.Checkmark.OrStyle(style.CheckboxCheckmark);
|
this.Checkmark = this.Checkmark.OrStyle(style.CheckboxCheckmark);
|
||||||
this.TextOffsetX = this.TextOffsetX.OrStyle(style.CheckboxTextOffsetX);
|
this.TextOffsetX = this.TextOffsetX.OrStyle(style.CheckboxTextOffsetX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// The panel that this dropdown contains. It will be displayed upon pressing the dropdown button.
|
/// The panel that this dropdown contains. It will be displayed upon pressing the dropdown button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Panel Panel;
|
public readonly Panel Panel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This property stores whether the dropdown is currently opened or not
|
/// This property stores whether the dropdown is currently opened or not
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,6 +43,12 @@ namespace MLEM.Ui.Elements {
|
||||||
this.OnAreaUpdated += e => this.Panel.PositionOffset = new Vector2(0, e.Area.Height / this.Scale);
|
this.OnAreaUpdated += e => this.Panel.PositionOffset = new Vector2(0, e.Area.Height / this.Scale);
|
||||||
this.OnOpenedOrClosed += e => this.Priority = this.IsOpen ? 10000 : 0;
|
this.OnOpenedOrClosed += e => this.Priority = this.IsOpen ? 10000 : 0;
|
||||||
this.OnPressed += e => this.IsOpen = !this.IsOpen;
|
this.OnPressed += e => this.IsOpen = !this.IsOpen;
|
||||||
|
this.GetGamepadNextElement = (dir, usualNext) => {
|
||||||
|
// Force navigate down to our first child if we're open
|
||||||
|
if (this.IsOpen && dir == Direction2.Down)
|
||||||
|
return this.Panel.GetChildren().FirstOrDefault(c => c.CanBeSelected) ?? usualNext;
|
||||||
|
return usualNext;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -54,11 +60,13 @@ namespace MLEM.Ui.Elements {
|
||||||
// Since the dropdown causes elements to be over each other,
|
// Since the dropdown causes elements to be over each other,
|
||||||
// usual gamepad code doesn't apply
|
// usual gamepad code doesn't apply
|
||||||
element.GetGamepadNextElement = (dir, usualNext) => {
|
element.GetGamepadNextElement = (dir, usualNext) => {
|
||||||
|
if (dir == Direction2.Left || dir == Direction2.Right)
|
||||||
|
return null;
|
||||||
if (dir == Direction2.Up) {
|
if (dir == Direction2.Up) {
|
||||||
var prev = element.GetOlderSibling();
|
var prev = element.GetOlderSibling(e => e.CanBeSelected);
|
||||||
return prev ?? this;
|
return prev ?? this;
|
||||||
} else if (dir == Direction2.Down) {
|
} else if (dir == Direction2.Down) {
|
||||||
return element.GetSiblings(e => e.GetOlderSibling() == element).FirstOrDefault();
|
return element.GetSiblings(e => e.CanBeSelected && e.GetOlderSibling(s => s.CanBeSelected) == element).FirstOrDefault();
|
||||||
}
|
}
|
||||||
return usualNext;
|
return usualNext;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
@ -32,22 +33,7 @@ namespace MLEM.Ui.Elements {
|
||||||
internal set {
|
internal set {
|
||||||
this.system = value;
|
this.system = value;
|
||||||
this.Controls = value?.Controls;
|
this.Controls = value?.Controls;
|
||||||
this.Style = value?.Style;
|
this.Style = this.Style.OrStyle(value?.Style);
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// This Element's current <see cref="UiStyle"/>.
|
|
||||||
/// When this value is changed, <see cref="InitStyle"/> is called.
|
|
||||||
/// Note that this value is automatically set to the <see cref="UiSystem"/>'s ui style when it is changed.
|
|
||||||
/// </summary>
|
|
||||||
public UiStyle Style {
|
|
||||||
get => this.style;
|
|
||||||
set {
|
|
||||||
if (this.style != value) {
|
|
||||||
this.style = value;
|
|
||||||
if (value != null)
|
|
||||||
this.InitStyle(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -165,7 +151,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// Set this property to <c>true</c> to cause this element to be hidden.
|
/// Set this property to <c>true</c> to cause this element to be hidden.
|
||||||
/// Hidden elements don't receive input events, aren't rendered and don't factor into auto-anchoring.
|
/// Hidden elements don't receive input events, aren't rendered and don't factor into auto-anchoring.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsHidden {
|
public virtual bool IsHidden {
|
||||||
get => this.isHidden;
|
get => this.isHidden;
|
||||||
set {
|
set {
|
||||||
if (this.isHidden == value)
|
if (this.isHidden == value)
|
||||||
|
@ -198,69 +184,84 @@ namespace MLEM.Ui.Elements {
|
||||||
/// The call that this element should make to <see cref="SpriteBatch"/> to begin drawing.
|
/// The call that this element should make to <see cref="SpriteBatch"/> to begin drawing.
|
||||||
/// Note that, when this is non-null, a new <see cref="SpriteBatch.Begin"/> call is used for this element.
|
/// Note that, when this is non-null, a new <see cref="SpriteBatch.Begin"/> call is used for this element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
[Obsolete("BeginImpl is deprecated. You can create a custom element class and override Draw instead.")]
|
||||||
public BeginDelegate BeginImpl;
|
public BeginDelegate BeginImpl;
|
||||||
|
#pragma warning restore CS0618
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disallow the element from being selected.
|
/// Set this field to false to disallow the element from being selected.
|
||||||
/// An unselectable element is skipped by automatic navigation and its <see cref="OnSelected"/> callback will never be called.
|
/// An unselectable element is skipped by automatic navigation and its <see cref="OnSelected"/> callback will never be called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanBeSelected = true;
|
public virtual bool CanBeSelected { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disallow the element from reacting to being moused over.
|
/// Set this field to false to disallow the element from reacting to being moused over.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanBeMoused = true;
|
public virtual bool CanBeMoused { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disallow this element's <see cref="OnPressed"/> and <see cref="OnSecondaryPressed"/> events to be called.
|
/// Set this field to false to disallow this element's <see cref="OnPressed"/> and <see cref="OnSecondaryPressed"/> events to be called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanBePressed = true;
|
public virtual bool CanBePressed { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to cause auto-anchored siblings to ignore this element as a possible anchor point.
|
/// Set this field to false to cause auto-anchored siblings to ignore this element as a possible anchor point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanAutoAnchorsAttach = true;
|
public virtual bool CanAutoAnchorsAttach { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause this element's width to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
/// Set this field to true to cause this element's width to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||||
/// To use this element's <see cref="Size"/>'s X coordinate as a minimum or maximum width rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
/// To use this element's <see cref="Size"/>'s X coordinate as a minimum or maximum width rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SetWidthBasedOnChildren;
|
public virtual bool SetWidthBasedOnChildren { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause this element's height to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
/// Set this field to true to cause this element's height to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||||
/// To use this element's <see cref="Size"/>'s Y coordinate as a minimum or maximum height rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
/// To use this element's <see cref="Size"/>'s Y coordinate as a minimum or maximum height rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SetHeightBasedOnChildren;
|
public virtual bool SetHeightBasedOnChildren { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled, the resulting width or height will always be greather than or equal to this element's <see cref="Size"/>.
|
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled, the resulting width or height will always be greather than or equal to this element's <see cref="Size"/>.
|
||||||
/// For example, if an element's <see cref="Size"/>'s Y coordinate is set to 20, but there is only one child with a height of 10 in it, the element's height would be shrunk to 10 if this value was false, but would remain at 20 if it was true.
|
/// For example, if an element's <see cref="Size"/>'s Y coordinate is set to 20, but there is only one child with a height of 10 in it, the element's height would be shrunk to 10 if this value was false, but would remain at 20 if it was true.
|
||||||
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TreatSizeAsMinimum;
|
public virtual bool TreatSizeAsMinimum { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/>are enabled, the resulting width or height weill always be less than or equal to this element's <see cref="Size"/>.
|
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/>are enabled, the resulting width or height weill always be less than or equal to this element's <see cref="Size"/>.
|
||||||
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TreatSizeAsMaximum;
|
public virtual bool TreatSizeAsMaximum { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause this element's final display area to never exceed that of its <see cref="Parent"/>.
|
/// Set this field to true to cause this element's final display area to never exceed that of its <see cref="Parent"/>.
|
||||||
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
|
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
|
||||||
/// This can be useful if an element should fill the remaining area of a parent exactly.
|
/// This can be useful if an element should fill the remaining area of a parent exactly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PreventParentSpill;
|
public virtual bool PreventParentSpill { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The transparency (alpha value) that this element is rendered with.
|
/// The transparency (alpha value) that this element is rendered with.
|
||||||
/// Note that, when <see cref="Draw"/> is called, this alpha value is multiplied with the <see cref="Parent"/>'s alpha value and passed down to this element's <see cref="Children"/>.
|
/// Note that, when <see cref="Draw"/> is called, this alpha value is multiplied with the <see cref="Parent"/>'s alpha value and passed down to this element's <see cref="Children"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float DrawAlpha = 1;
|
public virtual float DrawAlpha { get; set; } = 1;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores whether this element is currently being moused over or touched.
|
/// Stores whether this element is currently being moused over or touched.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMouseOver { get; protected set; }
|
public bool IsMouseOver { get; protected set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores whether this element is its <see cref="Root"/>'s <see cref="RootElement.SelectedElement"/>.
|
/// Returns whether this element is its <see cref="Root"/>'s <see cref="RootElement.SelectedElement"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsSelected { get; protected set; }
|
public bool IsSelected => this.Root.SelectedElement == this;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns whether this element's <see cref="SetAreaDirty"/> method has been recently called and its area has not been updated since then using <see cref="UpdateAreaIfDirty"/> or <see cref="ForceUpdateArea"/>.
|
/// Returns whether this element's <see cref="SetAreaDirty"/> method has been recently called and its area has not been updated since then using <see cref="UpdateAreaIfDirty"/> or <see cref="ForceUpdateArea"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AreaDirty { get; private set; }
|
public bool AreaDirty { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This Element's current <see cref="UiStyle"/>.
|
||||||
|
/// When this property is set, <see cref="InitStyle"/> is called.
|
||||||
|
/// </summary>
|
||||||
|
public StyleProp<UiStyle> Style {
|
||||||
|
get => this.style;
|
||||||
|
set {
|
||||||
|
this.style = value;
|
||||||
|
if (this.style.HasValue())
|
||||||
|
this.InitStyle(this.style);
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A style property that contains the selection indicator that is displayed on this element if it is the <see cref="RootElement.SelectedElement"/>
|
/// A style property that contains the selection indicator that is displayed on this element if it is the <see cref="RootElement.SelectedElement"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -342,6 +343,10 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericCallback OnAreaUpdated;
|
public GenericCallback OnAreaUpdated;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Event that is called when this element's <see cref="InitStyle"/> method is called while setting the <see cref="Style"/>.
|
||||||
|
/// </summary>
|
||||||
|
public GenericCallback OnStyleInit;
|
||||||
|
/// <summary>
|
||||||
/// Event that is called when the element that is currently being moused changes within the ui system.
|
/// Event that is called when the element that is currently being moused changes within the ui system.
|
||||||
/// Note that the event fired doesn't necessarily correlate to this specific element.
|
/// Note that the event fired doesn't necessarily correlate to this specific element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -398,8 +403,14 @@ namespace MLEM.Ui.Elements {
|
||||||
/// The input handler that this element's <see cref="Controls"/> use
|
/// The input handler that this element's <see cref="Controls"/> use
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected InputHandler Input => this.Controls.Input;
|
protected InputHandler Input => this.Controls.Input;
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="ChildPaddedArea"/> of this element's <see cref="Parent"/>, or the <see cref="UiSystem.Viewport"/> if this element has no parent.
|
||||||
|
/// This value is the one that is passed to <see cref="CalcActualSize"/> during <see cref="ForceUpdateArea"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected RectangleF ParentArea => this.Parent?.ChildPaddedArea ?? (RectangleF) this.system.Viewport;
|
||||||
|
|
||||||
private readonly List<Element> children = new List<Element>();
|
private readonly List<Element> children = new List<Element>();
|
||||||
|
private readonly Stopwatch stopwatch = new Stopwatch();
|
||||||
private bool sortedChildrenDirty;
|
private bool sortedChildrenDirty;
|
||||||
private IList<Element> sortedChildren;
|
private IList<Element> sortedChildren;
|
||||||
private UiSystem system;
|
private UiSystem system;
|
||||||
|
@ -409,7 +420,7 @@ namespace MLEM.Ui.Elements {
|
||||||
private RectangleF area;
|
private RectangleF area;
|
||||||
private bool isHidden;
|
private bool isHidden;
|
||||||
private int priority;
|
private int priority;
|
||||||
private UiStyle style;
|
private StyleProp<UiStyle> style;
|
||||||
private StyleProp<Padding> childPadding;
|
private StyleProp<Padding> childPadding;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -427,8 +438,6 @@ namespace MLEM.Ui.Elements {
|
||||||
this.OnMouseExit += element => this.IsMouseOver = false;
|
this.OnMouseExit += element => this.IsMouseOver = false;
|
||||||
this.OnTouchEnter += element => this.IsMouseOver = true;
|
this.OnTouchEnter += element => this.IsMouseOver = true;
|
||||||
this.OnTouchExit += element => this.IsMouseOver = false;
|
this.OnTouchExit += element => this.IsMouseOver = false;
|
||||||
this.OnSelected += element => this.IsSelected = true;
|
|
||||||
this.OnDeselected += element => this.IsSelected = false;
|
|
||||||
this.GetTabNextElement += (backward, next) => next;
|
this.GetTabNextElement += (backward, next) => next;
|
||||||
this.GetGamepadNextElement += (dir, next) => next;
|
this.GetGamepadNextElement += (dir, next) => next;
|
||||||
|
|
||||||
|
@ -525,7 +534,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetAreaDirty() {
|
public void SetAreaDirty() {
|
||||||
this.AreaDirty = true;
|
this.AreaDirty = true;
|
||||||
this.Parent?.OnChildAreaDirty(this);
|
this.Parent?.OnChildAreaDirty(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -552,9 +561,9 @@ namespace MLEM.Ui.Elements {
|
||||||
// which would cause our ForceUpdateArea code to be run twice, so we only update our parent instead
|
// which would cause our ForceUpdateArea code to be run twice, so we only update our parent instead
|
||||||
if (this.Parent != null && this.Parent.UpdateAreaIfDirty())
|
if (this.Parent != null && this.Parent.UpdateAreaIfDirty())
|
||||||
return;
|
return;
|
||||||
this.System.Stopwatch.Restart();
|
this.stopwatch.Restart();
|
||||||
|
|
||||||
var parentArea = this.Parent != null ? this.Parent.ChildPaddedArea : (RectangleF) this.system.Viewport;
|
var parentArea = this.ParentArea;
|
||||||
var parentCenterX = parentArea.X + parentArea.Width / 2;
|
var parentCenterX = parentArea.X + parentArea.Width / 2;
|
||||||
var parentCenterY = parentArea.Y + parentArea.Height / 2;
|
var parentCenterY = parentArea.Y + parentArea.Height / 2;
|
||||||
var actualSize = this.CalcActualSize(parentArea);
|
var actualSize = this.CalcActualSize(parentArea);
|
||||||
|
@ -562,8 +571,8 @@ namespace MLEM.Ui.Elements {
|
||||||
var recursion = 0;
|
var recursion = 0;
|
||||||
UpdateDisplayArea(actualSize);
|
UpdateDisplayArea(actualSize);
|
||||||
|
|
||||||
this.System.Stopwatch.Stop();
|
this.stopwatch.Stop();
|
||||||
this.System.Metrics.ForceAreaUpdateTime += this.System.Stopwatch.Elapsed;
|
this.System.Metrics.ForceAreaUpdateTime += this.stopwatch.Elapsed;
|
||||||
this.System.Metrics.ForceAreaUpdates++;
|
this.System.Metrics.ForceAreaUpdates++;
|
||||||
|
|
||||||
void UpdateDisplayArea(Vector2 newSize) {
|
void UpdateDisplayArea(Vector2 newSize) {
|
||||||
|
@ -916,8 +925,10 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <param name="depthStencilState">The depth stencil state that is used for drawing</param>
|
/// <param name="depthStencilState">The depth stencil state that is used for drawing</param>
|
||||||
/// <param name="matrix">The transformation matrix that is used for drawing</param>
|
/// <param name="matrix">The transformation matrix that is used for drawing</param>
|
||||||
public void DrawTransformed(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
public void DrawTransformed(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
||||||
|
#pragma warning disable CS0618
|
||||||
var customDraw = this.BeginImpl != null || this.Transform != Matrix.Identity;
|
var customDraw = this.BeginImpl != null || this.Transform != Matrix.Identity;
|
||||||
var mat = this.Transform * matrix;
|
var mat = this.Transform * matrix;
|
||||||
|
// TODO ending and beginning again when the matrix changes isn't ideal (https://github.com/MonoGame/MonoGame/issues/3156)
|
||||||
if (customDraw) {
|
if (customDraw) {
|
||||||
// end the usual draw so that we can begin our own
|
// end the usual draw so that we can begin our own
|
||||||
batch.End();
|
batch.End();
|
||||||
|
@ -928,6 +939,7 @@ namespace MLEM.Ui.Elements {
|
||||||
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, null, effect, mat);
|
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, null, effect, mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
|
||||||
// draw content in custom begin call
|
// draw content in custom begin call
|
||||||
this.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, mat);
|
this.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, mat);
|
||||||
|
@ -978,6 +990,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <param name="effect">The effect that is used for drawing</param>
|
/// <param name="effect">The effect that is used for drawing</param>
|
||||||
/// <param name="depthStencilState">The depth stencil state that is used for drawing</param>
|
/// <param name="depthStencilState">The depth stencil state that is used for drawing</param>
|
||||||
/// <param name="matrix">The transformation matrix that is used for drawing</param>
|
/// <param name="matrix">The transformation matrix that is used for drawing</param>
|
||||||
|
[Obsolete("DrawEarly is deprecated. For custom implementations, see Panel.Draw for how to replace this method.")]
|
||||||
public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
||||||
foreach (var child in this.GetRelevantChildren()) {
|
foreach (var child in this.GetRelevantChildren()) {
|
||||||
if (!child.IsHidden)
|
if (!child.IsHidden)
|
||||||
|
@ -1053,16 +1066,22 @@ namespace MLEM.Ui.Elements {
|
||||||
this.SelectionIndicator = this.SelectionIndicator.OrStyle(style.SelectionIndicator);
|
this.SelectionIndicator = this.SelectionIndicator.OrStyle(style.SelectionIndicator);
|
||||||
this.ActionSound = this.ActionSound.OrStyle(style.ActionSound);
|
this.ActionSound = this.ActionSound.OrStyle(style.ActionSound);
|
||||||
this.SecondActionSound = this.SecondActionSound.OrStyle(style.ActionSound);
|
this.SecondActionSound = this.SecondActionSound.OrStyle(style.ActionSound);
|
||||||
|
|
||||||
|
this.System?.InvokeOnElementStyleInit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A method that gets called by this element's <see cref="Children"/> when their <see cref="SetAreaDirty"/> methods get called.
|
/// A method that gets called by this element's <see cref="Children"/> or any of its grandchildren when their <see cref="SetAreaDirty"/> methods get called.
|
||||||
/// Note that the element's area might already be dirty, which will not stop this method from being called.
|
/// Note that the element's area might already be dirty, which will not stop this method from being called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="child">The child whose area is being set dirty</param>
|
/// <param name="child">The child whose area is being set dirty.</param>
|
||||||
protected virtual void OnChildAreaDirty(Element child) {
|
/// <param name="grandchild">Whether the <paramref name="child"/> is a grandchild of this element, rather than a direct child.</param>
|
||||||
if (child.Anchor >= Anchor.AutoLeft || this.SetWidthBasedOnChildren || this.SetHeightBasedOnChildren)
|
protected virtual void OnChildAreaDirty(Element child, bool grandchild) {
|
||||||
this.SetAreaDirty();
|
if (!grandchild) {
|
||||||
|
if (child.Anchor >= Anchor.AutoLeft || this.SetWidthBasedOnChildren || this.SetHeightBasedOnChildren)
|
||||||
|
this.SetAreaDirty();
|
||||||
|
}
|
||||||
|
this.Parent?.OnChildAreaDirty(child, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1150,6 +1169,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <param name="effect">The effect used for drawing</param>
|
/// <param name="effect">The effect used for drawing</param>
|
||||||
/// <param name="depthStencilState">The depth stencil state used for drawing</param>
|
/// <param name="depthStencilState">The depth stencil state used for drawing</param>
|
||||||
/// <param name="matrix">The transform matrix used for drawing</param>
|
/// <param name="matrix">The transform matrix used for drawing</param>
|
||||||
|
[Obsolete("BeginDelegate is deprecated. You can create a custom element class and override Draw instead.")]
|
||||||
public delegate void BeginDelegate(Element element, GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix);
|
public delegate void BeginDelegate(Element element, GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,28 +115,31 @@ namespace MLEM.Ui.Elements {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="KeybindButton(MLEM.Ui.Anchor,Microsoft.Xna.Framework.Vector2,MLEM.Input.Keybind,MLEM.Input.InputHandler,string,MLEM.Input.Keybind,string,System.Func{MLEM.Input.GenericInput,string},int)"/>
|
||||||
|
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, GenericInput unbindKey = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null, int index = 0) {
|
||||||
|
return KeybindButton(anchor, size, keybind, inputHandler, activePlaceholder, new Keybind(unbindKey), unboundPlaceholder, inputName, index);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="Button"/> that acts as a way to input a custom value for a <see cref="Keybind"/>.
|
/// Creates a <see cref="Button"/> that acts as a way to input a custom value for a <see cref="Keybind"/>.
|
||||||
/// Note that only the first <see cref="Keybind.Combination"/> of the given keybind is displayed and edited, all others are ignored. The exception is that, if <paramref name="unbindKey"/> is set, unbinding the keybind clears all combinations.
|
/// Note that only the <see cref="Keybind.Combination"/> at index <paramref name="index"/> of the given keybind is displayed and edited, all others are ignored.
|
||||||
/// Inputting custom keybinds using this element supports <see cref="ModifierKey"/>-based modifiers and any <see cref="GenericInput"/>-based keys.
|
/// Inputting custom keybinds using this element supports <see cref="ModifierKey"/>-based modifiers and any <see cref="GenericInput"/>-based keys.
|
||||||
|
/// The keybind button's current state can be retrieved using the "Active" <see cref="GenericDataHolder.GetData{T}"/> key, which stores a bool that indicates whether the button is currently waiting for a new value to be assigned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="anchor">The button's anchor</param>
|
/// <param name="anchor">The button's anchor</param>
|
||||||
/// <param name="size">The button's size</param>
|
/// <param name="size">The button's size</param>
|
||||||
/// <param name="keybind">The keybind that this button should represent</param>
|
/// <param name="keybind">The keybind that this button should represent</param>
|
||||||
/// <param name="inputHandler">The input handler to query inputs with</param>
|
/// <param name="inputHandler">The input handler to query inputs with</param>
|
||||||
/// <param name="activePlaceholder">A placeholder text that is displayed while the keybind is being edited</param>
|
/// <param name="activePlaceholder">A placeholder text that is displayed while the keybind is being edited</param>
|
||||||
/// <param name="unbindKey">An optional generic input that allows the keybind value to be unbound, clearing all combinations</param>
|
/// <param name="unbind">An optional keybind to press that allows the keybind value to be unbound, clearing the combination</param>
|
||||||
/// <param name="unboundPlaceholder">A placeholder text that is displayed if the keybind is unbound</param>
|
/// <param name="unboundPlaceholder">A placeholder text that is displayed if the keybind is unbound</param>
|
||||||
/// <param name="inputName">An optional function to give each input a display name that is easier to read. If this is null, <see cref="GenericInput.ToString"/> is used.</param>
|
/// <param name="inputName">An optional function to give each input a display name that is easier to read. If this is null, <see cref="GenericInput.ToString"/> is used.</param>
|
||||||
|
/// <param name="index">The index in the <paramref name="keybind"/> that the button should display. Note that, if the index is greater than the amount of combinations, combinations entered using this button will be stored at an earlier index.</param>
|
||||||
/// <returns>A keybind button with the given settings</returns>
|
/// <returns>A keybind button with the given settings</returns>
|
||||||
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, GenericInput unbindKey = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null) {
|
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, Keybind unbind = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null, int index = 0) {
|
||||||
string GetCurrentName() {
|
string GetCurrentName() => keybind.TryGetCombination(index, out var combination) ? combination.ToString(" + ", inputName) : unboundPlaceholder;
|
||||||
var combination = keybind.GetCombinations().FirstOrDefault();
|
|
||||||
return combination?.ToString(" + ", inputName) ?? unboundPlaceholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
var button = new Button(anchor, size, GetCurrentName());
|
var button = new Button(anchor, size, GetCurrentName());
|
||||||
var active = false;
|
|
||||||
var activeNext = false;
|
var activeNext = false;
|
||||||
button.OnPressed = e => {
|
button.OnPressed = e => {
|
||||||
button.Text.Text = activePlaceholder;
|
button.Text.Text = activePlaceholder;
|
||||||
|
@ -144,22 +147,24 @@ namespace MLEM.Ui.Elements {
|
||||||
};
|
};
|
||||||
button.OnUpdated = (e, time) => {
|
button.OnUpdated = (e, time) => {
|
||||||
if (activeNext) {
|
if (activeNext) {
|
||||||
active = true;
|
button.SetData("Active", true);
|
||||||
activeNext = false;
|
activeNext = false;
|
||||||
} else if (active) {
|
} else if (button.GetData<bool>("Active")) {
|
||||||
if (unbindKey != default && inputHandler.IsPressed(unbindKey)) {
|
if (unbind != null && unbind.IsPressed(inputHandler)) {
|
||||||
keybind.Clear();
|
keybind.Remove((c, i) => i == index);
|
||||||
button.Text.Text = unboundPlaceholder;
|
button.Text.Text = unboundPlaceholder;
|
||||||
active = false;
|
button.SetData("Active", false);
|
||||||
} else if (inputHandler.InputsPressed.Length > 0) {
|
} else if (inputHandler.InputsPressed.Length > 0) {
|
||||||
var key = inputHandler.InputsPressed.FirstOrDefault(i => !i.IsModifier());
|
var key = inputHandler.InputsPressed.FirstOrDefault(i => !i.IsModifier());
|
||||||
if (key != default) {
|
if (key != default) {
|
||||||
var mods = inputHandler.InputsDown.Where(i => i.IsModifier());
|
var mods = inputHandler.InputsDown.Where(i => i.IsModifier());
|
||||||
keybind.Remove((c, i) => i == 0).Add(key, mods.ToArray());
|
keybind.Remove((c, i) => i == index).Insert(index, key, mods.ToArray());
|
||||||
button.Text.Text = GetCurrentName();
|
button.Text.Text = GetCurrentName();
|
||||||
active = false;
|
button.SetData("Active", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
button.Text.Text = GetCurrentName();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return button;
|
return button;
|
||||||
|
|
|
@ -13,7 +13,6 @@ namespace MLEM.Ui.Elements {
|
||||||
/// A panel element to be used inside of a <see cref="UiSystem"/>.
|
/// A panel element to be used inside of a <see cref="UiSystem"/>.
|
||||||
/// The panel is a complex element that displays a box as a background to all of its child elements.
|
/// The panel is a complex element that displays a box as a background to all of its child elements.
|
||||||
/// Additionally, a panel can be set to <see cref="scrollOverflow"/> on construction, which causes all elements that don't fit into the panel to be hidden until scrolled to using a <see cref="ScrollBar"/>.
|
/// Additionally, a panel can be set to <see cref="scrollOverflow"/> on construction, which causes all elements that don't fit into the panel to be hidden until scrolled to using a <see cref="ScrollBar"/>.
|
||||||
/// As this behavior is accomplished using a <see cref="RenderTarget2D"/>, scrolling panels need to have their <see cref="DrawEarly"/> methods called using <see cref="UiSystem.DrawEarly"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Panel : Element {
|
public class Panel : Element {
|
||||||
|
|
||||||
|
@ -79,13 +78,13 @@ namespace MLEM.Ui.Elements {
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle automatic element selection, the scroller needs to scroll to the right location
|
// handle automatic element selection, the scroller needs to scroll to the right location
|
||||||
this.OnSelectedElementChanged += (element, otherElement) => {
|
this.OnSelectedElementChanged += (_, e) => {
|
||||||
if (!this.Controls.IsAutoNavMode)
|
if (!this.Controls.IsAutoNavMode)
|
||||||
return;
|
return;
|
||||||
if (otherElement == null || !otherElement.GetParentTree().Contains(this))
|
if (e == null || !e.GetParentTree().Contains(this))
|
||||||
return;
|
return;
|
||||||
var firstChild = this.Children.First(c => c != this.ScrollBar);
|
var firstChild = this.Children.First(c => c != this.ScrollBar);
|
||||||
this.ScrollBar.CurrentValue = (otherElement.Area.Bottom - firstChild.Area.Top - this.Area.Height / 2) / this.Scale;
|
this.ScrollBar.CurrentValue = (e.Area.Center.Y - this.Area.Height / 2 - firstChild.Area.Top) / e.Scale + this.ChildPadding.Value.Height / 2;
|
||||||
};
|
};
|
||||||
this.AddChild(this.ScrollBar);
|
this.AddChild(this.ScrollBar);
|
||||||
}
|
}
|
||||||
|
@ -119,8 +118,9 @@ namespace MLEM.Ui.Elements {
|
||||||
if (!this.scrollOverflow)
|
if (!this.scrollOverflow)
|
||||||
return;
|
return;
|
||||||
var offset = new Vector2(0, -this.ScrollBar.CurrentValue);
|
var offset = new Vector2(0, -this.ScrollBar.CurrentValue);
|
||||||
foreach (var child in this.GetChildren(c => c != this.ScrollBar, true)) {
|
// we ignore false grandchildren so that the children of the scroll bar stay in place
|
||||||
if (child.ScrollOffset != offset) {
|
foreach (var child in this.GetChildren(c => c != this.ScrollBar, true, true)) {
|
||||||
|
if (!child.ScrollOffset.Equals(offset, Epsilon)) {
|
||||||
child.ScrollOffset = offset;
|
child.ScrollOffset = offset;
|
||||||
this.relevantChildrenDirty = true;
|
this.relevantChildrenDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -158,23 +158,23 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
protected override void OnChildAreaDirty(Element child, bool grandchild) {
|
||||||
if (this.Texture.HasValue())
|
base.OnChildAreaDirty(child, grandchild);
|
||||||
batch.Draw(this.Texture, this.DisplayArea, this.DrawColor.OrDefault(Color.White) * alpha, this.Scale);
|
// we only need to scroll when a grandchild changes, since all of our children are forced
|
||||||
// if we handle overflow, draw using the render target in DrawUnbound
|
// to be auto-anchored and so will automatically propagate their changes up to us
|
||||||
if (!this.scrollOverflow || this.renderTarget == null) {
|
if (grandchild)
|
||||||
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix);
|
this.ScrollChildren();
|
||||||
} else {
|
|
||||||
// draw the actual render target (don't apply the alpha here because it's already drawn onto with alpha)
|
|
||||||
batch.Draw(this.renderTarget, this.GetRenderTargetArea(), Color.White);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
|
||||||
this.UpdateAreaIfDirty();
|
// draw children onto the render target if we have one
|
||||||
if (this.scrollOverflow && this.renderTarget != null) {
|
if (this.scrollOverflow && this.renderTarget != null) {
|
||||||
// draw children onto the render target
|
this.UpdateAreaIfDirty();
|
||||||
|
batch.End();
|
||||||
|
// force render target usage to preserve so that previous content isn't cleared
|
||||||
|
var lastUsage = batch.GraphicsDevice.PresentationParameters.RenderTargetUsage;
|
||||||
|
batch.GraphicsDevice.PresentationParameters.RenderTargetUsage = RenderTargetUsage.PreserveContents;
|
||||||
using (batch.GraphicsDevice.WithRenderTarget(this.renderTarget)) {
|
using (batch.GraphicsDevice.WithRenderTarget(this.renderTarget)) {
|
||||||
batch.GraphicsDevice.Clear(Color.Transparent);
|
batch.GraphicsDevice.Clear(Color.Transparent);
|
||||||
// offset children by the render target's location
|
// offset children by the render target's location
|
||||||
|
@ -185,8 +185,19 @@ namespace MLEM.Ui.Elements {
|
||||||
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, trans);
|
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, trans);
|
||||||
batch.End();
|
batch.End();
|
||||||
}
|
}
|
||||||
|
batch.GraphicsDevice.PresentationParameters.RenderTargetUsage = lastUsage;
|
||||||
|
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, null, effect, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Texture.HasValue())
|
||||||
|
batch.Draw(this.Texture, this.DisplayArea, this.DrawColor.OrDefault(Color.White) * alpha, this.Scale);
|
||||||
|
// if we handle overflow, draw using the render target in DrawUnbound
|
||||||
|
if (!this.scrollOverflow || this.renderTarget == null) {
|
||||||
|
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix);
|
||||||
|
} else {
|
||||||
|
// draw the actual render target (don't apply the alpha here because it's already drawn onto with alpha)
|
||||||
|
batch.Draw(this.renderTarget, this.GetRenderTargetArea(), Color.White);
|
||||||
}
|
}
|
||||||
base.DrawEarly(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using MLEM.Extensions;
|
||||||
using MLEM.Font;
|
using MLEM.Font;
|
||||||
using MLEM.Formatting;
|
using MLEM.Formatting;
|
||||||
using MLEM.Formatting.Codes;
|
using MLEM.Formatting.Codes;
|
||||||
|
@ -24,8 +25,7 @@ namespace MLEM.Ui.Elements {
|
||||||
get => this.regularFont;
|
get => this.regularFont;
|
||||||
set {
|
set {
|
||||||
this.regularFont = value;
|
this.regularFont = value;
|
||||||
this.SetAreaDirty();
|
this.SetTextDirty();
|
||||||
this.TokenizedText = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -59,8 +59,7 @@ namespace MLEM.Ui.Elements {
|
||||||
if (this.text != value) {
|
if (this.text != value) {
|
||||||
this.text = value;
|
this.text = value;
|
||||||
this.IsHidden = string.IsNullOrWhiteSpace(this.text);
|
this.IsHidden = string.IsNullOrWhiteSpace(this.text);
|
||||||
this.SetAreaDirty();
|
this.SetTextDirty();
|
||||||
this.TokenizedText = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,17 +90,16 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="TextAlignment"/> that this paragraph's text should be rendered with
|
/// The <see cref="TextAlignment"/> that this paragraph's text should be rendered with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextAlignment Alignment {
|
public StyleProp<TextAlignment> Alignment {
|
||||||
get => this.alignment;
|
get => this.alignment;
|
||||||
set {
|
set {
|
||||||
this.alignment = value;
|
this.alignment = value;
|
||||||
this.SetAreaDirty();
|
this.SetTextDirty();
|
||||||
this.TokenizedText = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string text;
|
private string text;
|
||||||
private TextAlignment alignment;
|
private StyleProp<TextAlignment> alignment;
|
||||||
private StyleProp<GenericFont> regularFont;
|
private StyleProp<GenericFont> regularFont;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -160,6 +158,7 @@ namespace MLEM.Ui.Elements {
|
||||||
this.RegularFont = this.RegularFont.OrStyle(style.Font ?? throw new NotSupportedException("Paragraphs cannot use ui styles that don't have a font. Please supply a custom font by setting UiStyle.Font."));
|
this.RegularFont = this.RegularFont.OrStyle(style.Font ?? throw new NotSupportedException("Paragraphs cannot use ui styles that don't have a font. Please supply a custom font by setting UiStyle.Font."));
|
||||||
this.TextScale = this.TextScale.OrStyle(style.TextScale);
|
this.TextScale = this.TextScale.OrStyle(style.TextScale);
|
||||||
this.TextColor = this.TextColor.OrStyle(style.TextColor);
|
this.TextColor = this.TextColor.OrStyle(style.TextColor);
|
||||||
|
this.Alignment = this.Alignment.OrStyle(style.TextAlignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -187,13 +186,24 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A helper method that causes the <see cref="TokenizedText"/> to be reset.
|
||||||
|
/// Additionally, <see cref="Element.SetAreaDirty"/> if this paragraph's area has changed enough to warrant it, or if it has any <see cref="Link"/> children.
|
||||||
|
/// </summary>
|
||||||
|
protected void SetTextDirty() {
|
||||||
|
this.TokenizedText = null;
|
||||||
|
// only set our area dirty if our size changed as a result of this action
|
||||||
|
if (!this.AreaDirty && !this.CalcActualSize(this.ParentArea).Equals(this.DisplayArea.Size, Epsilon))
|
||||||
|
this.SetAreaDirty();
|
||||||
|
}
|
||||||
|
|
||||||
private void QueryTextCallback() {
|
private void QueryTextCallback() {
|
||||||
if (this.GetTextCallback != null)
|
if (this.GetTextCallback != null)
|
||||||
this.Text = this.GetTextCallback(this);
|
this.Text = this.GetTextCallback(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetAlignmentOffset() {
|
private float GetAlignmentOffset() {
|
||||||
switch (this.Alignment) {
|
switch (this.Alignment.Value) {
|
||||||
case TextAlignment.Center:
|
case TextAlignment.Center:
|
||||||
return this.DisplayArea.Width / 2;
|
return this.DisplayArea.Width / 2;
|
||||||
case TextAlignment.Right:
|
case TextAlignment.Right:
|
||||||
|
@ -257,7 +267,10 @@ namespace MLEM.Ui.Elements {
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
return ret;
|
return ret;
|
||||||
// check if any of our token's parts are hovered
|
// check if any of our token's parts are hovered
|
||||||
foreach (var rect in this.Token.GetArea(this.Parent.DisplayArea.Location, this.Scale * this.textScale)) {
|
var location = this.Parent.DisplayArea.Location;
|
||||||
|
if (this.Parent is Paragraph p)
|
||||||
|
location.X += p.GetAlignmentOffset();
|
||||||
|
foreach (var rect in this.Token.GetArea(location, this.Scale * this.textScale)) {
|
||||||
if (rect.Contains(this.TransformInverse(position)))
|
if (rect.Contains(this.TransformInverse(position)))
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,14 +137,14 @@ namespace MLEM.Ui.Elements {
|
||||||
|
|
||||||
// MOUSE INPUT
|
// MOUSE INPUT
|
||||||
var moused = this.Controls.MousedElement;
|
var moused = this.Controls.MousedElement;
|
||||||
if (moused == this && this.Controls.Input.IsMouseButtonPressed(MouseButton.Left)) {
|
if (moused == this && this.Input.IsMouseButtonPressed(MouseButton.Left)) {
|
||||||
this.isMouseHeld = true;
|
this.isMouseHeld = true;
|
||||||
this.scrollStartOffset = this.TransformInverseAll(this.Input.MousePosition.ToVector2()) - this.ScrollerPosition;
|
this.scrollStartOffset = this.TransformInverseAll(this.Input.ViewportMousePosition.ToVector2()) - this.ScrollerPosition;
|
||||||
} else if (this.isMouseHeld && !this.Controls.Input.IsMouseButtonDown(MouseButton.Left)) {
|
} else if (this.isMouseHeld && !this.Input.IsMouseButtonDown(MouseButton.Left)) {
|
||||||
this.isMouseHeld = false;
|
this.isMouseHeld = false;
|
||||||
}
|
}
|
||||||
if (this.isMouseHeld)
|
if (this.isMouseHeld)
|
||||||
this.ScrollToPos(this.TransformInverseAll(this.Input.MousePosition.ToVector2()));
|
this.ScrollToPos(this.TransformInverseAll(this.Input.ViewportMousePosition.ToVector2()));
|
||||||
if (!this.Horizontal && moused != null && (moused == this.Parent || moused.GetParentTree().Contains(this.Parent))) {
|
if (!this.Horizontal && moused != null && (moused == this.Parent || moused.GetParentTree().Contains(this.Parent))) {
|
||||||
var scroll = this.Input.LastScrollWheel - this.Input.ScrollWheel;
|
var scroll = this.Input.LastScrollWheel - this.Input.ScrollWheel;
|
||||||
if (scroll != 0)
|
if (scroll != 0)
|
||||||
|
@ -154,7 +154,7 @@ namespace MLEM.Ui.Elements {
|
||||||
// TOUCH INPUT
|
// TOUCH INPUT
|
||||||
if (!this.Horizontal) {
|
if (!this.Horizontal) {
|
||||||
// are we dragging on top of the panel?
|
// are we dragging on top of the panel?
|
||||||
if (this.Input.GetGesture(GestureType.VerticalDrag, out var drag)) {
|
if (this.Input.GetViewportGesture(GestureType.VerticalDrag, out var drag)) {
|
||||||
// if the element under the drag's start position is on top of the panel, start dragging
|
// if the element under the drag's start position is on top of the panel, start dragging
|
||||||
var touched = this.Parent.GetElementUnderPos(this.TransformInverseAll(drag.Position));
|
var touched = this.Parent.GetElementUnderPos(this.TransformInverseAll(drag.Position));
|
||||||
if (touched != null && touched != this)
|
if (touched != null && touched != this)
|
||||||
|
@ -167,11 +167,11 @@ namespace MLEM.Ui.Elements {
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.Input.TouchState.Count <= 0) {
|
if (this.Input.ViewportTouchState.Count <= 0) {
|
||||||
// if no touch has occured this tick, then reset the variable
|
// if no touch has occured this tick, then reset the variable
|
||||||
this.isTouchHeld = false;
|
this.isTouchHeld = false;
|
||||||
} else {
|
} else {
|
||||||
foreach (var loc in this.Input.TouchState) {
|
foreach (var loc in this.Input.ViewportTouchState) {
|
||||||
var pos = this.TransformInverseAll(loc.Position);
|
var pos = this.TransformInverseAll(loc.Position);
|
||||||
// if we just started touching and are on top of the scroller, then we should start scrolling
|
// if we just started touching and are on top of the scroller, then we should start scrolling
|
||||||
if (this.DisplayArea.Contains(pos) && !loc.TryGetPreviousLocation(out _)) {
|
if (this.DisplayArea.Contains(pos) && !loc.TryGetPreviousLocation(out _)) {
|
||||||
|
|
|
@ -32,9 +32,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// <param name="size">The image's size</param>
|
/// <param name="size">The image's size</param>
|
||||||
/// <param name="animation">The sprite group to display</param>
|
/// <param name="animation">The sprite group to display</param>
|
||||||
/// <param name="scaleToImage">Whether this image element should scale to the texture</param>
|
/// <param name="scaleToImage">Whether this image element should scale to the texture</param>
|
||||||
public SpriteAnimationImage(Anchor anchor, Vector2 size, SpriteAnimation animation, bool scaleToImage = false) :
|
public SpriteAnimationImage(Anchor anchor, Vector2 size, SpriteAnimation animation, bool scaleToImage = false) : this(anchor, size, new SpriteAnimationGroup().Add(animation, () => true), scaleToImage) {}
|
||||||
this(anchor, size, new SpriteAnimationGroup().Add(animation, () => true), scaleToImage) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(GameTime time) {
|
public override void Update(GameTime time) {
|
||||||
|
|
|
@ -16,8 +16,7 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="anchor">The group's anchor.</param>
|
/// <param name="anchor">The group's anchor.</param>
|
||||||
/// <param name="size">The group's size.</param>
|
/// <param name="size">The group's size.</param>
|
||||||
public SquishingGroup(Anchor anchor, Vector2 size) : base(anchor, size, false) {
|
public SquishingGroup(Anchor anchor, Vector2 size) : base(anchor, size, false) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void SetAreaAndUpdateChildren(RectangleF area) {
|
public override void SetAreaAndUpdateChildren(RectangleF area) {
|
||||||
|
@ -31,9 +30,10 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnChildAreaDirty(Element child) {
|
protected override void OnChildAreaDirty(Element child, bool grandchild) {
|
||||||
base.OnChildAreaDirty(child);
|
base.OnChildAreaDirty(child, grandchild);
|
||||||
this.SetAreaDirty();
|
if (!grandchild)
|
||||||
|
this.SetAreaDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool SquishChild(Element element, out RectangleF squishedArea) {
|
private static bool SquishChild(Element element, out RectangleF squishedArea) {
|
||||||
|
|
|
@ -423,7 +423,7 @@ namespace MLEM.Ui.Elements {
|
||||||
var maxWidth = this.DisplayArea.Width / this.Scale - this.TextOffsetX * 2;
|
var maxWidth = this.DisplayArea.Width / this.Scale - this.TextOffsetX * 2;
|
||||||
if (this.Multiline) {
|
if (this.Multiline) {
|
||||||
// soft wrap if we're multiline
|
// soft wrap if we're multiline
|
||||||
this.splitText = this.Font.Value.SplitStringSeparate(this.text.ToString(), maxWidth, this.TextScale).ToArray();
|
this.splitText = this.Font.Value.SplitStringSeparate(this.text, maxWidth, this.TextScale).ToArray();
|
||||||
this.displayedText = string.Join("\n", this.splitText);
|
this.displayedText = string.Join("\n", this.splitText);
|
||||||
this.UpdateCaretData();
|
this.UpdateCaretData();
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// not multiline, so scroll horizontally based on caret position
|
// not multiline, so scroll horizontally based on caret position
|
||||||
if (this.Font.Value.MeasureString(this.text.ToString()).X * this.TextScale > maxWidth) {
|
if (this.Font.Value.MeasureString(this.text).X * this.TextScale > maxWidth) {
|
||||||
if (this.textOffset > this.CaretPos) {
|
if (this.textOffset > this.CaretPos) {
|
||||||
// if we're moving the caret to the left
|
// if we're moving the caret to the left
|
||||||
this.textOffset = this.CaretPos;
|
this.textOffset = this.CaretPos;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using MLEM.Input;
|
||||||
using MLEM.Ui.Style;
|
using MLEM.Ui.Style;
|
||||||
|
|
||||||
namespace MLEM.Ui.Elements {
|
namespace MLEM.Ui.Elements {
|
||||||
|
@ -15,6 +16,10 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StyleProp<Vector2> MouseOffset;
|
public StyleProp<Vector2> MouseOffset;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The offset that this tooltip's top center coordinate should have from the bottom center of the element snapped to when <see cref="DisplayInAutoNavMode"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public StyleProp<Vector2> AutoNavOffset;
|
||||||
|
/// <summary>
|
||||||
/// The amount of time that the mouse has to be over an element before it appears
|
/// The amount of time that the mouse has to be over an element before it appears
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StyleProp<TimeSpan> Delay;
|
public StyleProp<TimeSpan> Delay;
|
||||||
|
@ -22,9 +27,24 @@ namespace MLEM.Ui.Elements {
|
||||||
/// The paragraph of text that this tooltip displays
|
/// The paragraph of text that this tooltip displays
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Paragraph Paragraph;
|
public Paragraph Paragraph;
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this tooltip should display when <see cref="UiControls.IsAutoNavMode"/> is true, which is when the UI is being controlled using a keyboard or gamepad.
|
||||||
|
/// If this tooltip is displayed in auto-nav mode, it will display below the selected element with the <see cref="AutoNavOffset"/> applied.
|
||||||
|
/// </summary>
|
||||||
|
public bool DisplayInAutoNavMode;
|
||||||
|
/// <summary>
|
||||||
|
/// The position that this tooltip should be following (or snapped to) instead of the <see cref="InputHandler.ViewportMousePosition"/>.
|
||||||
|
/// If this value is unset, <see cref="InputHandler.ViewportMousePosition"/> will be used as the snap position.
|
||||||
|
/// Note that <see cref="MouseOffset"/> is still applied with this value set.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector2? SnapPosition { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsHidden => this.autoHidden || base.IsHidden;
|
||||||
|
|
||||||
private TimeSpan delayCountdown;
|
private TimeSpan delayCountdown;
|
||||||
private bool autoHidden;
|
private bool autoHidden;
|
||||||
|
private Element snapElement;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new tooltip with the given settings
|
/// Creates a new tooltip with the given settings
|
||||||
|
@ -59,6 +79,7 @@ namespace MLEM.Ui.Elements {
|
||||||
if (this.delayCountdown <= TimeSpan.Zero) {
|
if (this.delayCountdown <= TimeSpan.Zero) {
|
||||||
this.IsHidden = false;
|
this.IsHidden = false;
|
||||||
this.UpdateAutoHidden();
|
this.UpdateAutoHidden();
|
||||||
|
this.SnapPositionToMouse();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.UpdateAutoHidden();
|
this.UpdateAutoHidden();
|
||||||
|
@ -78,6 +99,7 @@ namespace MLEM.Ui.Elements {
|
||||||
base.InitStyle(style);
|
base.InitStyle(style);
|
||||||
this.Texture = this.Texture.OrStyle(style.TooltipBackground);
|
this.Texture = this.Texture.OrStyle(style.TooltipBackground);
|
||||||
this.MouseOffset = this.MouseOffset.OrStyle(style.TooltipOffset);
|
this.MouseOffset = this.MouseOffset.OrStyle(style.TooltipOffset);
|
||||||
|
this.AutoNavOffset = this.AutoNavOffset.OrStyle(style.TooltipAutoNavOffset);
|
||||||
this.Delay = this.Delay.OrStyle(style.TooltipDelay);
|
this.Delay = this.Delay.OrStyle(style.TooltipDelay);
|
||||||
this.ChildPadding = this.ChildPadding.OrStyle(style.TooltipChildPadding);
|
this.ChildPadding = this.ChildPadding.OrStyle(style.TooltipChildPadding);
|
||||||
if (this.Paragraph != null) {
|
if (this.Paragraph != null) {
|
||||||
|
@ -87,11 +109,20 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Causes this tooltip's position to be snapped to the mouse position.
|
/// Causes this tooltip's position to be snapped to the mouse position, or the <see cref="snapElement"/> if <see cref="DisplayInAutoNavMode"/> is true, or the <see cref="SnapPosition"/> if set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SnapPositionToMouse() {
|
public void SnapPositionToMouse() {
|
||||||
|
Vector2 snapPosition;
|
||||||
|
if (this.snapElement != null) {
|
||||||
|
// center our snap position below the snap element
|
||||||
|
snapPosition = new Vector2(this.snapElement.DisplayArea.Center.X, this.snapElement.DisplayArea.Bottom) + this.AutoNavOffset;
|
||||||
|
snapPosition.X -= this.DisplayArea.Width / 2F;
|
||||||
|
} else {
|
||||||
|
snapPosition = (this.SnapPosition ?? this.Input.ViewportMousePosition.ToVector2()) + this.MouseOffset.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var viewport = this.System.Viewport;
|
var viewport = this.System.Viewport;
|
||||||
var offset = (this.Input.MousePosition.ToVector2() + this.MouseOffset.Value) / this.Scale;
|
var offset = snapPosition / this.Scale;
|
||||||
if (offset.X < viewport.X)
|
if (offset.X < viewport.X)
|
||||||
offset.X = viewport.X;
|
offset.X = viewport.X;
|
||||||
if (offset.Y < viewport.Y)
|
if (offset.Y < viewport.Y)
|
||||||
|
@ -108,8 +139,10 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="system">The system to add this tooltip to</param>
|
/// <param name="system">The system to add this tooltip to</param>
|
||||||
/// <param name="name">The name that this tooltip should use</param>
|
/// <param name="name">The name that this tooltip should use</param>
|
||||||
public void Display(UiSystem system, string name) {
|
/// <returns>Whether this tooltip was successfully added, which is not the case if it is already being displayed currently.</returns>
|
||||||
system.Add(name, this);
|
public bool Display(UiSystem system, string name) {
|
||||||
|
if (system.Add(name, this) == null)
|
||||||
|
return false;
|
||||||
if (this.Delay <= TimeSpan.Zero) {
|
if (this.Delay <= TimeSpan.Zero) {
|
||||||
this.IsHidden = false;
|
this.IsHidden = false;
|
||||||
this.SnapPositionToMouse();
|
this.SnapPositionToMouse();
|
||||||
|
@ -118,6 +151,7 @@ namespace MLEM.Ui.Elements {
|
||||||
this.delayCountdown = this.Delay;
|
this.delayCountdown = this.Delay;
|
||||||
}
|
}
|
||||||
this.autoHidden = false;
|
this.autoHidden = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -134,8 +168,20 @@ namespace MLEM.Ui.Elements {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="elementToHover">The element that should automatically cause the tooltip to appear and disappear when hovered and not hovered, respectively</param>
|
/// <param name="elementToHover">The element that should automatically cause the tooltip to appear and disappear when hovered and not hovered, respectively</param>
|
||||||
public void AddToElement(Element elementToHover) {
|
public void AddToElement(Element elementToHover) {
|
||||||
elementToHover.OnMouseEnter += element => this.Display(element.System, element.GetType().Name + "Tooltip");
|
elementToHover.OnMouseEnter += e => this.Display(e.System, $"{e.GetType().Name}Tooltip");
|
||||||
elementToHover.OnMouseExit += element => this.Remove();
|
elementToHover.OnMouseExit += e => this.Remove();
|
||||||
|
elementToHover.OnSelected += e => {
|
||||||
|
if (this.DisplayInAutoNavMode) {
|
||||||
|
this.snapElement = e;
|
||||||
|
this.Display(e.System, $"{e.GetType().Name}Tooltip");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
elementToHover.OnDeselected += e => {
|
||||||
|
if (this.DisplayInAutoNavMode) {
|
||||||
|
this.Remove();
|
||||||
|
this.snapElement = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init(Element elementToHover) {
|
private void Init(Element elementToHover) {
|
||||||
|
@ -159,10 +205,8 @@ namespace MLEM.Ui.Elements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.autoHidden != shouldBeHidden) {
|
if (this.autoHidden != shouldBeHidden) {
|
||||||
// only auto-hide if IsHidden wasn't changed manually
|
|
||||||
if (this.IsHidden == this.autoHidden)
|
|
||||||
this.IsHidden = shouldBeHidden;
|
|
||||||
this.autoHidden = shouldBeHidden;
|
this.autoHidden = shouldBeHidden;
|
||||||
|
this.SetAreaDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Ellpeck</Authors>
|
<Authors>Ellpeck</Authors>
|
||||||
<Description>A mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types</Description>
|
<Description>A mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types</Description>
|
||||||
|
@ -16,16 +16,16 @@
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="TextCopy" Version="4.3.1" />
|
<PackageReference Include="TextCopy" Version="4.3.1" />
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
|
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
|
|
|
@ -27,8 +27,7 @@ namespace MLEM.Ui.Style {
|
||||||
/// To create a style property with a lower priority, use <see cref="OrStyle(T,byte)"/> on an existing priority, or use <see cref="None"/>.
|
/// To create a style property with a lower priority, use <see cref="OrStyle(T,byte)"/> on an existing priority, or use <see cref="None"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The custom style to apply</param>
|
/// <param name="value">The custom style to apply</param>
|
||||||
public StyleProp(T value) : this(value, byte.MaxValue) {
|
public StyleProp(T value) : this(value, byte.MaxValue) {}
|
||||||
}
|
|
||||||
|
|
||||||
private StyleProp(T value, byte priority) {
|
private StyleProp(T value, byte priority) {
|
||||||
this.Value = value;
|
this.Value = value;
|
||||||
|
@ -76,6 +75,7 @@ namespace MLEM.Ui.Style {
|
||||||
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
|
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
|
||||||
/// <param name="other">An object to compare with this object.</param>
|
/// <param name="other">An object to compare with this object.</param>
|
||||||
/// <returns>true if the current object is equal to the <paramref name="other">other</paramref> parameter; otherwise, false.</returns>
|
/// <returns>true if the current object is equal to the <paramref name="other">other</paramref> parameter; otherwise, false.</returns>
|
||||||
|
[Obsolete("StyleProp equality is ambiguous as it is not clear whether priority is taken into account. Compare Values instead.")]
|
||||||
public bool Equals(StyleProp<T> other) {
|
public bool Equals(StyleProp<T> other) {
|
||||||
return EqualityComparer<T>.Default.Equals(this.Value, other.Value);
|
return EqualityComparer<T>.Default.Equals(this.Value, other.Value);
|
||||||
}
|
}
|
||||||
|
@ -83,15 +83,19 @@ namespace MLEM.Ui.Style {
|
||||||
/// <summary>Indicates whether this instance and a specified object are equal.</summary>
|
/// <summary>Indicates whether this instance and a specified object are equal.</summary>
|
||||||
/// <param name="obj">The object to compare with the current instance.</param>
|
/// <param name="obj">The object to compare with the current instance.</param>
|
||||||
/// <returns>true if <paramref name="obj">obj</paramref> and this instance are the same type and represent the same value; otherwise, false.</returns>
|
/// <returns>true if <paramref name="obj">obj</paramref> and this instance are the same type and represent the same value; otherwise, false.</returns>
|
||||||
|
[Obsolete("StyleProp equality is ambiguous as it is not clear whether priority is taken into account. Compare Values instead.")]
|
||||||
|
#pragma warning disable CS0809
|
||||||
public override bool Equals(object obj) {
|
public override bool Equals(object obj) {
|
||||||
return obj is StyleProp<T> other && this.Equals(other);
|
return obj is StyleProp<T> other && this.Equals(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns the hash code for this instance.</summary>
|
/// <summary>Returns the hash code for this instance.</summary>
|
||||||
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
||||||
|
[Obsolete("StyleProp equality is ambiguous as it is not clear whether priority is taken into account. Compare Values instead.")]
|
||||||
public override int GetHashCode() {
|
public override int GetHashCode() {
|
||||||
return EqualityComparer<T>.Default.GetHashCode(this.Value);
|
return EqualityComparer<T>.Default.GetHashCode(this.Value);
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CS0809
|
||||||
|
|
||||||
/// <summary>Returns the fully qualified type name of this instance.</summary>
|
/// <summary>Returns the fully qualified type name of this instance.</summary>
|
||||||
/// <returns>The fully qualified type name.</returns>
|
/// <returns>The fully qualified type name.</returns>
|
||||||
|
@ -123,6 +127,7 @@ namespace MLEM.Ui.Style {
|
||||||
/// <param name="left">The left style property.</param>
|
/// <param name="left">The left style property.</param>
|
||||||
/// <param name="right">The right style property.</param>
|
/// <param name="right">The right style property.</param>
|
||||||
/// <returns>Whether the two style properties are equal.</returns>
|
/// <returns>Whether the two style properties are equal.</returns>
|
||||||
|
[Obsolete("StyleProp equality is ambiguous as it is not clear whether priority is taken into account. Compare Values instead.")]
|
||||||
public static bool operator ==(StyleProp<T> left, StyleProp<T> right) {
|
public static bool operator ==(StyleProp<T> left, StyleProp<T> right) {
|
||||||
return left.Equals(right);
|
return left.Equals(right);
|
||||||
}
|
}
|
||||||
|
@ -133,6 +138,7 @@ namespace MLEM.Ui.Style {
|
||||||
/// <param name="left">The left style property.</param>
|
/// <param name="left">The left style property.</param>
|
||||||
/// <param name="right">The right style property.</param>
|
/// <param name="right">The right style property.</param>
|
||||||
/// <returns>Whether the two style properties are not equal.</returns>
|
/// <returns>Whether the two style properties are not equal.</returns>
|
||||||
|
[Obsolete("StyleProp equality is ambiguous as it is not clear whether priority is taken into account. Compare Values instead.")]
|
||||||
public static bool operator !=(StyleProp<T> left, StyleProp<T> right) {
|
public static bool operator !=(StyleProp<T> left, StyleProp<T> right) {
|
||||||
return !left.Equals(right);
|
return !left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MLEM.Font;
|
using MLEM.Font;
|
||||||
using MLEM.Formatting;
|
using MLEM.Formatting;
|
||||||
|
using MLEM.Formatting.Codes;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
using MLEM.Textures;
|
using MLEM.Textures;
|
||||||
using MLEM.Ui.Elements;
|
using MLEM.Ui.Elements;
|
||||||
|
@ -110,6 +111,14 @@ namespace MLEM.Ui.Style {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color CheckboxHoveredColor = Color.LightGray;
|
public Color CheckboxHoveredColor = Color.LightGray;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The texture that the <see cref="Checkbox"/> element uses when it <see cref="Checkbox.IsDisabled"/>.
|
||||||
|
/// </summary>
|
||||||
|
public NinePatch CheckboxDisabledTexture;
|
||||||
|
/// <summary>
|
||||||
|
/// The color that the <see cref="Checkbox"/> element uses when it <see cref="Checkbox.IsDisabled"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color CheckboxDisabledColor = Color.Gray;
|
||||||
|
/// <summary>
|
||||||
/// The texture that the <see cref="Checkbox"/> element renders on top of its regular texture when it is <see cref="Checkbox.Checked"/>
|
/// The texture that the <see cref="Checkbox"/> element renders on top of its regular texture when it is <see cref="Checkbox.Checked"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextureRegion CheckboxCheckmark;
|
public TextureRegion CheckboxCheckmark;
|
||||||
|
@ -142,6 +151,10 @@ namespace MLEM.Ui.Style {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector2 TooltipOffset = new Vector2(8, 16);
|
public Vector2 TooltipOffset = new Vector2(8, 16);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The offset of the <see cref="Tooltip"/> element's top center coordinate from the bottom center of the element snapped to when <see cref="Tooltip.DisplayInAutoNavMode"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 TooltipAutoNavOffset = new Vector2(0, 8);
|
||||||
|
/// <summary>
|
||||||
/// The color that the text of a <see cref="Tooltip"/> should have
|
/// The color that the text of a <see cref="Tooltip"/> should have
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color TooltipTextColor = Color.White;
|
public Color TooltipTextColor = Color.White;
|
||||||
|
@ -191,11 +204,20 @@ namespace MLEM.Ui.Style {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color TextColor = Color.White;
|
public Color TextColor = Color.White;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The <see cref="TextAlignment"/> that a <see cref="Paragraph"/> should use by default.
|
||||||
|
/// </summary>
|
||||||
|
public TextAlignment TextAlignment;
|
||||||
|
/// <summary>
|
||||||
/// The <see cref="SoundEffectInfo"/> that should be played when an element's <see cref="Element.OnPressed"/> and <see cref="Element.OnSecondaryPressed"/> events are called.
|
/// The <see cref="SoundEffectInfo"/> that should be played when an element's <see cref="Element.OnPressed"/> and <see cref="Element.OnSecondaryPressed"/> events are called.
|
||||||
/// Note that this sound is only played if the callbacks have any subscribers.
|
/// Note that this sound is only played if the callbacks have any subscribers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SoundEffectInfo ActionSound;
|
public SoundEffectInfo ActionSound;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The color that a <see cref="Paragraph"/>'s <see cref="Paragraph.Link"/> codes should have.
|
||||||
|
/// This value is passed to <see cref="LinkCode"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color? LinkColor;
|
||||||
|
/// <summary>
|
||||||
/// A set of additional fonts that can be used for the <c><f FontName></c> formatting code
|
/// A set of additional fonts that can be used for the <c><f FontName></c> formatting code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, GenericFont> AdditionalFonts = new Dictionary<string, GenericFont>();
|
public Dictionary<string, GenericFont> AdditionalFonts = new Dictionary<string, GenericFont>();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
@ -19,36 +20,6 @@ namespace MLEM.Ui {
|
||||||
/// The input handler that is used for querying input
|
/// The input handler that is used for querying input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly InputHandler Input;
|
public readonly InputHandler Input;
|
||||||
/// <summary>
|
|
||||||
/// This value ist true if the <see cref="InputHandler"/> was created by this ui controls instance, or if it was passed in.
|
|
||||||
/// If the input handler was created by this instance, its <see cref="InputHandler.Update()"/> method should be called by us.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly bool IsInputOurs;
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="UiSystem"/> that this ui controls instance is controlling
|
|
||||||
/// </summary>
|
|
||||||
protected readonly UiSystem System;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="RootElement"/> that is currently active.
|
|
||||||
/// The active root element is the one with the highest <see cref="RootElement.Priority"/> that whose <see cref="RootElement.CanSelectContent"/> property is true.
|
|
||||||
/// </summary>
|
|
||||||
public RootElement ActiveRoot { get; protected set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="Element"/> that the mouse is currently over.
|
|
||||||
/// </summary>
|
|
||||||
public Element MousedElement { get; protected set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="Element"/> that is currently touched.
|
|
||||||
/// </summary>
|
|
||||||
public Element TouchedElement { get; protected set; }
|
|
||||||
private readonly Dictionary<string, Element> selectedElements = new Dictionary<string, Element>();
|
|
||||||
/// <summary>
|
|
||||||
/// The element that is currently selected.
|
|
||||||
/// This is the <see cref="RootElement.SelectedElement"/> of the <see cref="ActiveRoot"/>.
|
|
||||||
/// </summary>
|
|
||||||
public Element SelectedElement => this.GetSelectedElement(this.ActiveRoot);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of <see cref="Keys"/>, <see cref="Buttons"/> and/or <see cref="MouseButton"/> that act as the buttons on the keyboard which perform the <see cref="Element.OnPressed"/> action.
|
/// A list of <see cref="Keys"/>, <see cref="Buttons"/> and/or <see cref="MouseButton"/> that act as the buttons on the keyboard which perform the <see cref="Element.OnPressed"/> action.
|
||||||
/// If the <see cref="ModifierKey.Shift"/> is held, these buttons perform <see cref="Element.OnSecondaryPressed"/>.
|
/// If the <see cref="ModifierKey.Shift"/> is held, these buttons perform <see cref="Element.OnSecondaryPressed"/>.
|
||||||
|
@ -83,6 +54,25 @@ namespace MLEM.Ui {
|
||||||
/// This can be used to easily serialize and deserialize all ui keybinds.
|
/// This can be used to easily serialize and deserialize all ui keybinds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Keybind[] Keybinds;
|
public readonly Keybind[] Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="RootElement"/> that is currently active.
|
||||||
|
/// The active root element is the one with the highest <see cref="RootElement.Priority"/> that whose <see cref="RootElement.CanSelectContent"/> property is true.
|
||||||
|
/// </summary>
|
||||||
|
public RootElement ActiveRoot { get; protected set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Element"/> that the mouse is currently over.
|
||||||
|
/// </summary>
|
||||||
|
public Element MousedElement { get; protected set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Element"/> that is currently touched.
|
||||||
|
/// </summary>
|
||||||
|
public Element TouchedElement { get; protected set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The element that is currently selected.
|
||||||
|
/// This is the <see cref="RootElement.SelectedElement"/> of the <see cref="ActiveRoot"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Element SelectedElement => this.GetSelectedElement(this.ActiveRoot);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The zero-based index of the <see cref="GamePad"/> used for gamepad input.
|
/// The zero-based index of the <see cref="GamePad"/> used for gamepad input.
|
||||||
/// If this index is lower than 0, every connected gamepad will trigger input.
|
/// If this index is lower than 0, every connected gamepad will trigger input.
|
||||||
|
@ -111,9 +101,35 @@ namespace MLEM.Ui {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If this value is true, the ui controls are in automatic navigation mode.
|
/// If this value is true, the ui controls are in automatic navigation mode.
|
||||||
/// This means that the <see cref="UiStyle.SelectionIndicator"/> will be drawn around the <see cref="SelectedElement"/>.
|
/// This means that the <see cref="UiStyle.SelectionIndicator"/> will be drawn around the <see cref="SelectedElement"/>.
|
||||||
/// To set this value, use <see cref="SelectElement"/> or <see cref="RootElement.SelectElement"/>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAutoNavMode { get; internal set; }
|
public bool IsAutoNavMode {
|
||||||
|
get => this.isAutoNavMode;
|
||||||
|
set {
|
||||||
|
if (this.isAutoNavMode != value) {
|
||||||
|
this.isAutoNavMode = value;
|
||||||
|
this.AutoNavModeChanged?.Invoke(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An event that is raised when <see cref="IsAutoNavMode"/> is changed.
|
||||||
|
/// This can be used for custom actions like hiding the mouse cursor when automatic navigation is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<bool> AutoNavModeChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This value ist true if the <see cref="InputHandler"/> was created by this ui controls instance, or if it was passed in.
|
||||||
|
/// If the input handler was created by this instance, its <see cref="InputHandler.Update()"/> method should be called by us.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly bool IsInputOurs;
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="UiSystem"/> that this ui controls instance is controlling
|
||||||
|
/// </summary>
|
||||||
|
protected readonly UiSystem System;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, Element> selectedElements = new Dictionary<string, Element>();
|
||||||
|
private bool isAutoNavMode;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the ui controls.
|
/// Creates a new instance of the ui controls.
|
||||||
|
@ -139,11 +155,11 @@ namespace MLEM.Ui {
|
||||||
public virtual void Update() {
|
public virtual void Update() {
|
||||||
if (this.IsInputOurs)
|
if (this.IsInputOurs)
|
||||||
this.Input.Update();
|
this.Input.Update();
|
||||||
this.ActiveRoot = this.System.GetRootElements().FirstOrDefault(root => root.CanSelectContent && !root.Element.IsHidden);
|
this.ActiveRoot = this.System.GetRootElements().FirstOrDefault(root => !root.Element.IsHidden && root.CanSelectContent);
|
||||||
|
|
||||||
// MOUSE INPUT
|
// MOUSE INPUT
|
||||||
if (this.HandleMouse) {
|
if (this.HandleMouse) {
|
||||||
var mousedNow = this.GetElementUnderPos(this.Input.MousePosition.ToVector2());
|
var mousedNow = this.GetElementUnderPos(this.Input.ViewportMousePosition.ToVector2());
|
||||||
this.SetMousedElement(mousedNow);
|
this.SetMousedElement(mousedNow);
|
||||||
|
|
||||||
if (this.Input.IsMouseButtonPressed(MouseButton.Left)) {
|
if (this.Input.IsMouseButtonPressed(MouseButton.Left)) {
|
||||||
|
@ -184,22 +200,22 @@ namespace MLEM.Ui {
|
||||||
|
|
||||||
// TOUCH INPUT
|
// TOUCH INPUT
|
||||||
if (this.HandleTouch) {
|
if (this.HandleTouch) {
|
||||||
if (this.Input.GetGesture(GestureType.Tap, out var tap)) {
|
if (this.Input.GetViewportGesture(GestureType.Tap, out var tap)) {
|
||||||
this.IsAutoNavMode = false;
|
this.IsAutoNavMode = false;
|
||||||
var tapped = this.GetElementUnderPos(tap.Position);
|
var tapped = this.GetElementUnderPos(tap.Position);
|
||||||
this.SelectElement(this.ActiveRoot, tapped);
|
this.SelectElement(this.ActiveRoot, tapped);
|
||||||
if (tapped != null && tapped.CanBePressed)
|
if (tapped != null && tapped.CanBePressed)
|
||||||
this.System.InvokeOnElementPressed(tapped);
|
this.System.InvokeOnElementPressed(tapped);
|
||||||
} else if (this.Input.GetGesture(GestureType.Hold, out var hold)) {
|
} else if (this.Input.GetViewportGesture(GestureType.Hold, out var hold)) {
|
||||||
this.IsAutoNavMode = false;
|
this.IsAutoNavMode = false;
|
||||||
var held = this.GetElementUnderPos(hold.Position);
|
var held = this.GetElementUnderPos(hold.Position);
|
||||||
this.SelectElement(this.ActiveRoot, held);
|
this.SelectElement(this.ActiveRoot, held);
|
||||||
if (held != null && held.CanBePressed)
|
if (held != null && held.CanBePressed)
|
||||||
this.System.InvokeOnElementSecondaryPressed(held);
|
this.System.InvokeOnElementSecondaryPressed(held);
|
||||||
} else if (this.Input.TouchState.Count <= 0) {
|
} else if (this.Input.ViewportTouchState.Count <= 0) {
|
||||||
this.SetTouchedElement(null);
|
this.SetTouchedElement(null);
|
||||||
} else {
|
} else {
|
||||||
foreach (var location in this.Input.TouchState) {
|
foreach (var location in this.Input.ViewportTouchState) {
|
||||||
var element = this.GetElementUnderPos(location.Position);
|
var element = this.GetElementUnderPos(location.Position);
|
||||||
if (location.State == TouchLocationState.Pressed) {
|
if (location.State == TouchLocationState.Pressed) {
|
||||||
// start touching an element if we just touched down on it
|
// start touching an element if we just touched down on it
|
||||||
|
@ -259,6 +275,8 @@ namespace MLEM.Ui {
|
||||||
public void SelectElement(RootElement root, Element element, bool? autoNav = null) {
|
public void SelectElement(RootElement root, Element element, bool? autoNav = null) {
|
||||||
if (root == null)
|
if (root == null)
|
||||||
return;
|
return;
|
||||||
|
if (element != null && !element.CanBeSelected)
|
||||||
|
return;
|
||||||
var selected = this.GetSelectedElement(root);
|
var selected = this.GetSelectedElement(root);
|
||||||
if (selected == element)
|
if (selected == element)
|
||||||
return;
|
return;
|
||||||
|
@ -282,6 +300,8 @@ namespace MLEM.Ui {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="element">The element to set as moused</param>
|
/// <param name="element">The element to set as moused</param>
|
||||||
public void SetMousedElement(Element element) {
|
public void SetMousedElement(Element element) {
|
||||||
|
if (element != null && !element.CanBeMoused)
|
||||||
|
return;
|
||||||
if (element != this.MousedElement) {
|
if (element != this.MousedElement) {
|
||||||
if (this.MousedElement != null)
|
if (this.MousedElement != null)
|
||||||
this.System.InvokeOnElementMouseExit(this.MousedElement);
|
this.System.InvokeOnElementMouseExit(this.MousedElement);
|
||||||
|
@ -297,6 +317,8 @@ namespace MLEM.Ui {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="element">The element to set as touched</param>
|
/// <param name="element">The element to set as touched</param>
|
||||||
public void SetTouchedElement(Element element) {
|
public void SetTouchedElement(Element element) {
|
||||||
|
if (element != null && !element.CanBeMoused)
|
||||||
|
return;
|
||||||
if (element != this.TouchedElement) {
|
if (element != this.TouchedElement) {
|
||||||
if (this.TouchedElement != null)
|
if (this.TouchedElement != null)
|
||||||
this.System.InvokeOnElementTouchExit(this.TouchedElement);
|
this.System.InvokeOnElementTouchExit(this.TouchedElement);
|
||||||
|
@ -317,6 +339,8 @@ namespace MLEM.Ui {
|
||||||
if (root == null)
|
if (root == null)
|
||||||
return null;
|
return null;
|
||||||
this.selectedElements.TryGetValue(root.Name, out var element);
|
this.selectedElements.TryGetValue(root.Name, out var element);
|
||||||
|
if (element != null && !element.CanBeSelected)
|
||||||
|
return null;
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,11 +379,11 @@ namespace MLEM.Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the next element that should be selected during gamepad navigation, based on the <see cref="RectangleF"/> that we're looking for elements in.
|
/// Returns the next element that should be selected during gamepad navigation, based on the <see cref="Direction2"/> that we're looking for elements in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="searchArea">The area that we're looking for next elements in</param>
|
/// <param name="direction">The direction that we're looking for next elements in</param>
|
||||||
/// <returns>The first element found in that area</returns>
|
/// <returns>The first element found in that area</returns>
|
||||||
protected virtual Element GetGamepadNextElement(RectangleF searchArea) {
|
protected virtual Element GetGamepadNextElement(Direction2 direction) {
|
||||||
if (this.ActiveRoot == null)
|
if (this.ActiveRoot == null)
|
||||||
return null;
|
return null;
|
||||||
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element);
|
var children = this.ActiveRoot.Element.GetChildren(c => !c.IsHidden, true, true).Append(this.ActiveRoot.Element);
|
||||||
|
@ -367,14 +391,20 @@ namespace MLEM.Ui {
|
||||||
return children.FirstOrDefault(c => c.CanBeSelected);
|
return children.FirstOrDefault(c => c.CanBeSelected);
|
||||||
} else {
|
} else {
|
||||||
Element closest = null;
|
Element closest = null;
|
||||||
float closestDist = 0;
|
float closestPriority = 0;
|
||||||
foreach (var child in children) {
|
foreach (var child in children) {
|
||||||
if (!child.CanBeSelected || child == this.SelectedElement || !searchArea.Intersects(child.Area))
|
if (!child.CanBeSelected || child == this.SelectedElement)
|
||||||
continue;
|
continue;
|
||||||
var dist = Vector2.Distance(child.Area.Center, this.SelectedElement.Area.Center);
|
var (xOffset, yOffset) = child.Area.Center - this.SelectedElement.Area.Center;
|
||||||
if (closest == null || dist < closestDist) {
|
var angle = Math.Abs(direction.Angle() - (float) Math.Atan2(yOffset, xOffset));
|
||||||
|
if (angle >= MathHelper.PiOver2 - Element.Epsilon)
|
||||||
|
continue;
|
||||||
|
var distSq = child.Area.DistanceSquared(this.SelectedElement.Area);
|
||||||
|
// both distance and angle play a role in a destination button's priority, so we combine them
|
||||||
|
var priority = (distSq + 1) * (angle / MathHelper.PiOver2 + 1);
|
||||||
|
if (closest == null || priority < closestPriority) {
|
||||||
closest = child;
|
closest = child;
|
||||||
closestDist = dist;
|
closestPriority = priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return closest;
|
return closest;
|
||||||
|
@ -383,28 +413,7 @@ namespace MLEM.Ui {
|
||||||
|
|
||||||
private void HandleGamepadNextElement(Direction2 dir) {
|
private void HandleGamepadNextElement(Direction2 dir) {
|
||||||
this.IsAutoNavMode = true;
|
this.IsAutoNavMode = true;
|
||||||
RectangleF searchArea = default;
|
var next = this.GetGamepadNextElement(dir);
|
||||||
if (this.SelectedElement?.Root != null) {
|
|
||||||
searchArea = this.SelectedElement.Area;
|
|
||||||
var (_, _, width, height) = this.System.Viewport;
|
|
||||||
switch (dir) {
|
|
||||||
case Direction2.Down:
|
|
||||||
searchArea.Height += height;
|
|
||||||
break;
|
|
||||||
case Direction2.Left:
|
|
||||||
searchArea.X -= width;
|
|
||||||
searchArea.Width += width;
|
|
||||||
break;
|
|
||||||
case Direction2.Right:
|
|
||||||
searchArea.Width += width;
|
|
||||||
break;
|
|
||||||
case Direction2.Up:
|
|
||||||
searchArea.Y -= height;
|
|
||||||
searchArea.Height += height;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var next = this.GetGamepadNextElement(searchArea);
|
|
||||||
if (this.SelectedElement != null)
|
if (this.SelectedElement != null)
|
||||||
next = this.SelectedElement.GetGamepadNextElement(dir, next);
|
next = this.SelectedElement.GetGamepadNextElement(dir, next);
|
||||||
if (next != null)
|
if (next != null)
|
||||||
|
|
|
@ -23,9 +23,16 @@ namespace MLEM.Ui {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The viewport that this ui system is rendering inside of.
|
/// The viewport that this ui system is rendering inside of.
|
||||||
/// This is automatically updated during <see cref="GameWindow.ClientSizeChanged"/>
|
/// This is automatically updated during <see cref="GameWindow.ClientSizeChanged"/> by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Rectangle Viewport;
|
public Rectangle Viewport {
|
||||||
|
get => this.viewport;
|
||||||
|
set {
|
||||||
|
this.viewport = value;
|
||||||
|
foreach (var root in this.rootElements)
|
||||||
|
root.Element.ForceUpdateArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to true to cause the ui system and all of its elements to automatically scale up or down with greater and lower resolution, respectively.
|
/// Set this field to true to cause the ui system and all of its elements to automatically scale up or down with greater and lower resolution, respectively.
|
||||||
/// If this field is true, <see cref="AutoScaleReferenceSize"/> is used as the size that uses default <see cref="GlobalScale"/>
|
/// If this field is true, <see cref="AutoScaleReferenceSize"/> is used as the size that uses default <see cref="GlobalScale"/>
|
||||||
|
@ -59,10 +66,8 @@ namespace MLEM.Ui {
|
||||||
get => this.style;
|
get => this.style;
|
||||||
set {
|
set {
|
||||||
this.style = value;
|
this.style = value;
|
||||||
foreach (var root in this.rootElements) {
|
foreach (var root in this.rootElements)
|
||||||
root.Element.AndChildren(e => e.System = this);
|
root.Element.AndChildren(e => e.Style = e.Style.OrStyle(value));
|
||||||
root.Element.ForceUpdateArea();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -100,7 +105,7 @@ namespace MLEM.Ui {
|
||||||
public UiControls Controls;
|
public UiControls Controls;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The update and rendering statistics to be used for runtime debugging and profiling.
|
/// The update and rendering statistics to be used for runtime debugging and profiling.
|
||||||
/// The metrics are reset accordingly every frame: <see cref="UiMetrics.ResetUpdates"/> is called at the start of <see cref="Update"/>, and <see cref="UiMetrics.ResetDraws"/> is called at the start of <see cref="DrawEarly"/>, or at the start of <see cref="Draw"/> if <see cref="DrawEarly"/> was not called.
|
/// The metrics are reset accordingly every frame: <see cref="UiMetrics.ResetUpdates"/> is called at the start of <see cref="Update"/>, and <see cref="UiMetrics.ResetDraws"/> is called at the start of <see cref="Draw"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UiMetrics Metrics;
|
public UiMetrics Metrics;
|
||||||
|
|
||||||
|
@ -153,6 +158,10 @@ namespace MLEM.Ui {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Element.GenericCallback OnElementAreaUpdated;
|
public event Element.GenericCallback OnElementAreaUpdated;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Event that is called when an <see cref="Element"/>'s <see cref="Element.InitStyle"/> method is called while setting its <see cref="Element.Style"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Element.GenericCallback OnElementStyleInit;
|
||||||
|
/// <summary>
|
||||||
/// Event that is invoked when the <see cref="Element"/> that the mouse is currently over changes
|
/// Event that is invoked when the <see cref="Element"/> that the mouse is currently over changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Element.GenericCallback OnMousedElementChanged;
|
public event Element.GenericCallback OnMousedElementChanged;
|
||||||
|
@ -173,12 +182,12 @@ namespace MLEM.Ui {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event RootCallback OnRootRemoved;
|
public event RootCallback OnRootRemoved;
|
||||||
|
|
||||||
internal readonly Stopwatch Stopwatch = new Stopwatch();
|
|
||||||
|
|
||||||
private readonly List<RootElement> rootElements = new List<RootElement>();
|
private readonly List<RootElement> rootElements = new List<RootElement>();
|
||||||
|
private readonly Stopwatch stopwatch = new Stopwatch();
|
||||||
private float globalScale = 1;
|
private float globalScale = 1;
|
||||||
private bool drewEarly;
|
private bool drewEarly;
|
||||||
private UiStyle style;
|
private UiStyle style;
|
||||||
|
private Rectangle viewport;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new ui system with the given settings.
|
/// Creates a new ui system with the given settings.
|
||||||
|
@ -190,6 +199,7 @@ namespace MLEM.Ui {
|
||||||
public UiSystem(Game game, UiStyle style, InputHandler inputHandler = null, bool automaticViewport = true) : base(game) {
|
public UiSystem(Game game, UiStyle style, InputHandler inputHandler = null, bool automaticViewport = true) : base(game) {
|
||||||
this.Controls = new UiControls(this, inputHandler);
|
this.Controls = new UiControls(this, inputHandler);
|
||||||
this.style = style;
|
this.style = style;
|
||||||
|
|
||||||
this.OnElementDrawn += (e, time, batch, alpha) => e.OnDrawn?.Invoke(e, time, batch, alpha);
|
this.OnElementDrawn += (e, time, batch, alpha) => e.OnDrawn?.Invoke(e, time, batch, alpha);
|
||||||
this.OnElementUpdated += (e, time) => e.OnUpdated?.Invoke(e, time);
|
this.OnElementUpdated += (e, time) => e.OnUpdated?.Invoke(e, time);
|
||||||
this.OnElementPressed += e => e.OnPressed?.Invoke(e);
|
this.OnElementPressed += e => e.OnPressed?.Invoke(e);
|
||||||
|
@ -201,6 +211,7 @@ namespace MLEM.Ui {
|
||||||
this.OnElementTouchEnter += e => e.OnTouchEnter?.Invoke(e);
|
this.OnElementTouchEnter += e => e.OnTouchEnter?.Invoke(e);
|
||||||
this.OnElementTouchExit += e => e.OnTouchExit?.Invoke(e);
|
this.OnElementTouchExit += e => e.OnTouchExit?.Invoke(e);
|
||||||
this.OnElementAreaUpdated += e => e.OnAreaUpdated?.Invoke(e);
|
this.OnElementAreaUpdated += e => e.OnAreaUpdated?.Invoke(e);
|
||||||
|
this.OnElementStyleInit += e => e.OnStyleInit?.Invoke(e);
|
||||||
this.OnMousedElementChanged += e => this.ApplyToAll(t => t.OnMousedElementChanged?.Invoke(t, e));
|
this.OnMousedElementChanged += e => this.ApplyToAll(t => t.OnMousedElementChanged?.Invoke(t, e));
|
||||||
this.OnTouchedElementChanged += e => this.ApplyToAll(t => t.OnTouchedElementChanged?.Invoke(t, e));
|
this.OnTouchedElementChanged += e => this.ApplyToAll(t => t.OnTouchedElementChanged?.Invoke(t, e));
|
||||||
this.OnSelectedElementChanged += e => this.ApplyToAll(t => t.OnSelectedElementChanged?.Invoke(t, e));
|
this.OnSelectedElementChanged += e => this.ApplyToAll(t => t.OnSelectedElementChanged?.Invoke(t, e));
|
||||||
|
@ -216,6 +227,7 @@ namespace MLEM.Ui {
|
||||||
if (e.OnSecondaryPressed != null)
|
if (e.OnSecondaryPressed != null)
|
||||||
e.SecondActionSound.Value?.Play();
|
e.SecondActionSound.Value?.Play();
|
||||||
};
|
};
|
||||||
|
|
||||||
MlemPlatform.Current?.AddTextInputListener(game.Window, (sender, key, character) => this.ApplyToAll(e => e.OnTextInput?.Invoke(e, key, character)));
|
MlemPlatform.Current?.AddTextInputListener(game.Window, (sender, key, character) => this.ApplyToAll(e => e.OnTextInput?.Invoke(e, key, character)));
|
||||||
|
|
||||||
if (automaticViewport) {
|
if (automaticViewport) {
|
||||||
|
@ -223,14 +235,13 @@ namespace MLEM.Ui {
|
||||||
this.AutoScaleReferenceSize = this.Viewport.Size;
|
this.AutoScaleReferenceSize = this.Viewport.Size;
|
||||||
game.Window.ClientSizeChanged += (sender, args) => {
|
game.Window.ClientSizeChanged += (sender, args) => {
|
||||||
this.Viewport = new Rectangle(Point.Zero, game.Window.ClientBounds.Size);
|
this.Viewport = new Rectangle(Point.Zero, game.Window.ClientBounds.Size);
|
||||||
foreach (var root in this.rootElements)
|
|
||||||
root.Element.ForceUpdateArea();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.TextFormatter = new TextFormatter();
|
this.TextFormatter = new TextFormatter();
|
||||||
this.TextFormatter.Codes.Add(new Regex("<l(?: ([^>]+))?>"), (f, m, r) => new LinkCode(m, r, 1 / 16F, 0.85F,
|
this.TextFormatter.Codes.Add(new Regex("<l(?: ([^>]+))?>"), (f, m, r) => new LinkCode(m, r, 1 / 16F, 0.85F,
|
||||||
t => this.Controls.MousedElement is Paragraph.Link l1 && l1.Token == t || this.Controls.TouchedElement is Paragraph.Link l2 && l2.Token == t));
|
t => this.Controls.MousedElement is Paragraph.Link l1 && l1.Token == t || this.Controls.TouchedElement is Paragraph.Link l2 && l2.Token == t,
|
||||||
|
this.Style.LinkColor));
|
||||||
this.TextFormatter.Codes.Add(new Regex("<f ([^>]+)>"), (_, m, r) => new FontCode(m, r,
|
this.TextFormatter.Codes.Add(new Regex("<f ([^>]+)>"), (_, m, r) => new FontCode(m, r,
|
||||||
f => this.Style.AdditionalFonts != null && this.Style.AdditionalFonts.TryGetValue(m.Groups[1].Value, out var c) ? c : f));
|
f => this.Style.AdditionalFonts != null && this.Style.AdditionalFonts.TryGetValue(m.Groups[1].Value, out var c) ? c : f));
|
||||||
}
|
}
|
||||||
|
@ -241,14 +252,14 @@ namespace MLEM.Ui {
|
||||||
/// <param name="time">The game's time</param>
|
/// <param name="time">The game's time</param>
|
||||||
public override void Update(GameTime time) {
|
public override void Update(GameTime time) {
|
||||||
this.Metrics.ResetUpdates();
|
this.Metrics.ResetUpdates();
|
||||||
this.Stopwatch.Restart();
|
this.stopwatch.Restart();
|
||||||
|
|
||||||
this.Controls.Update();
|
this.Controls.Update();
|
||||||
for (var i = this.rootElements.Count - 1; i >= 0; i--)
|
for (var i = this.rootElements.Count - 1; i >= 0; i--)
|
||||||
this.rootElements[i].Element.Update(time);
|
this.rootElements[i].Element.Update(time);
|
||||||
|
|
||||||
this.Stopwatch.Stop();
|
this.stopwatch.Stop();
|
||||||
this.Metrics.UpdateTime += this.Stopwatch.Elapsed;
|
this.Metrics.UpdateTime += this.stopwatch.Elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -257,30 +268,30 @@ namespace MLEM.Ui {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The game's time</param>
|
/// <param name="time">The game's time</param>
|
||||||
/// <param name="batch">The sprite batch to use for drawing</param>
|
/// <param name="batch">The sprite batch to use for drawing</param>
|
||||||
|
[Obsolete("DrawEarly is deprecated. Calling it is not required anymore, and there is no replacement.")]
|
||||||
public void DrawEarly(GameTime time, SpriteBatch batch) {
|
public void DrawEarly(GameTime time, SpriteBatch batch) {
|
||||||
this.Metrics.ResetDraws();
|
this.Metrics.ResetDraws();
|
||||||
this.Stopwatch.Restart();
|
this.stopwatch.Restart();
|
||||||
|
|
||||||
foreach (var root in this.rootElements) {
|
foreach (var root in this.rootElements) {
|
||||||
if (!root.Element.IsHidden)
|
if (!root.Element.IsHidden)
|
||||||
root.Element.DrawEarly(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState, this.DepthStencilState, this.Effect, root.Transform);
|
root.Element.DrawEarly(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState, this.DepthStencilState, this.Effect, root.Transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Stopwatch.Stop();
|
this.stopwatch.Stop();
|
||||||
this.Metrics.DrawTime += this.Stopwatch.Elapsed;
|
this.Metrics.DrawTime += this.stopwatch.Elapsed;
|
||||||
this.drewEarly = true;
|
this.drewEarly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws any <see cref="Element"/>s onto the screen.
|
/// Draws any <see cref="Element"/>s onto the screen.
|
||||||
/// Note that, when using <see cref="Panel"/>s with a scroll bar, <see cref="DrawEarly"/> needs to be called as well.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The game's time</param>
|
/// <param name="time">The game's time</param>
|
||||||
/// <param name="batch">The sprite batch to use for drawing</param>
|
/// <param name="batch">The sprite batch to use for drawing</param>
|
||||||
public void Draw(GameTime time, SpriteBatch batch) {
|
public void Draw(GameTime time, SpriteBatch batch) {
|
||||||
if (!this.drewEarly)
|
if (!this.drewEarly)
|
||||||
this.Metrics.ResetDraws();
|
this.Metrics.ResetDraws();
|
||||||
this.Stopwatch.Restart();
|
this.stopwatch.Restart();
|
||||||
|
|
||||||
foreach (var root in this.rootElements) {
|
foreach (var root in this.rootElements) {
|
||||||
if (root.Element.IsHidden)
|
if (root.Element.IsHidden)
|
||||||
|
@ -291,8 +302,8 @@ namespace MLEM.Ui {
|
||||||
batch.End();
|
batch.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Stopwatch.Stop();
|
this.stopwatch.Stop();
|
||||||
this.Metrics.DrawTime += this.Stopwatch.Elapsed;
|
this.Metrics.DrawTime += this.stopwatch.Elapsed;
|
||||||
this.drewEarly = false;
|
this.drewEarly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,21 +391,69 @@ namespace MLEM.Ui {
|
||||||
root.Element.AndChildren(action);
|
root.Element.AndChildren(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvokeOnElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) => this.OnElementDrawn?.Invoke(element, time, batch, alpha);
|
internal void InvokeOnElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) {
|
||||||
internal void InvokeOnSelectedElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) => this.OnSelectedElementDrawn?.Invoke(element, time, batch, alpha);
|
this.OnElementDrawn?.Invoke(element, time, batch, alpha);
|
||||||
internal void InvokeOnElementUpdated(Element element, GameTime time) => this.OnElementUpdated?.Invoke(element, time);
|
}
|
||||||
internal void InvokeOnElementAreaUpdated(Element element) => this.OnElementAreaUpdated?.Invoke(element);
|
|
||||||
internal void InvokeOnElementPressed(Element element) => this.OnElementPressed?.Invoke(element);
|
internal void InvokeOnSelectedElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) {
|
||||||
internal void InvokeOnElementSecondaryPressed(Element element) => this.OnElementSecondaryPressed?.Invoke(element);
|
this.OnSelectedElementDrawn?.Invoke(element, time, batch, alpha);
|
||||||
internal void InvokeOnElementSelected(Element element) => this.OnElementSelected?.Invoke(element);
|
}
|
||||||
internal void InvokeOnElementDeselected(Element element) => this.OnElementDeselected?.Invoke(element);
|
|
||||||
internal void InvokeOnSelectedElementChanged(Element element) => this.OnSelectedElementChanged?.Invoke(element);
|
internal void InvokeOnElementUpdated(Element element, GameTime time) {
|
||||||
internal void InvokeOnElementMouseExit(Element element) => this.OnElementMouseExit?.Invoke(element);
|
this.OnElementUpdated?.Invoke(element, time);
|
||||||
internal void InvokeOnElementMouseEnter(Element element) => this.OnElementMouseEnter?.Invoke(element);
|
}
|
||||||
internal void InvokeOnMousedElementChanged(Element element) => this.OnMousedElementChanged?.Invoke(element);
|
|
||||||
internal void InvokeOnElementTouchExit(Element element) => this.OnElementTouchExit?.Invoke(element);
|
internal void InvokeOnElementAreaUpdated(Element element) {
|
||||||
internal void InvokeOnElementTouchEnter(Element element) => this.OnElementTouchEnter?.Invoke(element);
|
this.OnElementAreaUpdated?.Invoke(element);
|
||||||
internal void InvokeOnTouchedElementChanged(Element element) => this.OnTouchedElementChanged?.Invoke(element);
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementStyleInit(Element element) {
|
||||||
|
this.OnElementStyleInit?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementPressed(Element element) {
|
||||||
|
this.OnElementPressed?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementSecondaryPressed(Element element) {
|
||||||
|
this.OnElementSecondaryPressed?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementSelected(Element element) {
|
||||||
|
this.OnElementSelected?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementDeselected(Element element) {
|
||||||
|
this.OnElementDeselected?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnSelectedElementChanged(Element element) {
|
||||||
|
this.OnSelectedElementChanged?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementMouseExit(Element element) {
|
||||||
|
this.OnElementMouseExit?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementMouseEnter(Element element) {
|
||||||
|
this.OnElementMouseEnter?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnMousedElementChanged(Element element) {
|
||||||
|
this.OnMousedElementChanged?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementTouchExit(Element element) {
|
||||||
|
this.OnElementTouchExit?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnElementTouchEnter(Element element) {
|
||||||
|
this.OnElementTouchEnter?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnTouchedElementChanged(Element element) {
|
||||||
|
this.OnTouchedElementChanged?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate used for callbacks that involve a <see cref="RootElement"/>
|
/// A delegate used for callbacks that involve a <see cref="RootElement"/>
|
||||||
|
@ -475,7 +534,7 @@ namespace MLEM.Ui {
|
||||||
/// Determines whether this root element contains any children that <see cref="Elements.Element.CanBeSelected"/>.
|
/// Determines whether this root element contains any children that <see cref="Elements.Element.CanBeSelected"/>.
|
||||||
/// This value is automatically calculated.
|
/// This value is automatically calculated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanSelectContent { get; private set; }
|
public bool CanSelectContent => this.Element.CanBeSelected || this.Element.GetChildren(c => c.CanBeSelected, true).Any();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event that is invoked when a <see cref="Element"/> is added to this root element or any of its children.
|
/// Event that is invoked when a <see cref="Element"/> is added to this root element or any of its children.
|
||||||
|
@ -498,21 +557,6 @@ namespace MLEM.Ui {
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.Element = element;
|
this.Element = element;
|
||||||
this.System = system;
|
this.System = system;
|
||||||
|
|
||||||
this.OnElementAdded += e => {
|
|
||||||
if (e.CanBeSelected)
|
|
||||||
this.CanSelectContent = true;
|
|
||||||
};
|
|
||||||
this.OnElementRemoved += e => {
|
|
||||||
if (e.CanBeSelected) {
|
|
||||||
// check if removing this element removed all other selectable elements
|
|
||||||
foreach (var c in this.Element.GetChildren(regardGrandchildren: true)) {
|
|
||||||
if (c.CanBeSelected)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.CanSelectContent = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -534,10 +578,21 @@ namespace MLEM.Ui {
|
||||||
this.Transform = Matrix.CreateScale(scale, scale, 1) * Matrix.CreateTranslation(new Vector3((1 - scale) * (origin ?? this.Element.DisplayArea.Center), 0));
|
this.Transform = Matrix.CreateScale(scale, scale, 1) * Matrix.CreateTranslation(new Vector3((1 - scale) * (origin ?? this.Element.DisplayArea.Center), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvokeOnElementAdded(Element element) => this.OnElementAdded?.Invoke(element);
|
internal void InvokeOnElementAdded(Element element) {
|
||||||
internal void InvokeOnElementRemoved(Element element) => this.OnElementRemoved?.Invoke(element);
|
this.OnElementAdded?.Invoke(element);
|
||||||
internal void InvokeOnAddedToUi(UiSystem system) => this.OnAddedToUi?.Invoke(system);
|
}
|
||||||
internal void InvokeOnRemovedFromUi(UiSystem system) => this.OnRemovedFromUi?.Invoke(system);
|
|
||||||
|
internal void InvokeOnElementRemoved(Element element) {
|
||||||
|
this.OnElementRemoved?.Invoke(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnAddedToUi(UiSystem system) {
|
||||||
|
this.OnAddedToUi?.Invoke(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeOnRemovedFromUi(UiSystem system) {
|
||||||
|
this.OnRemovedFromUi?.Invoke(system);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -103,18 +103,14 @@ namespace MLEM.Animations {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
||||||
/// <param name="regions">The texture regions that should make up this animation</param>
|
/// <param name="regions">The texture regions that should make up this animation</param>
|
||||||
public SpriteAnimation(double timePerFrame, params TextureRegion[] regions) :
|
public SpriteAnimation(double timePerFrame, params TextureRegion[] regions) : this(Array.ConvertAll(regions, r => new AnimationFrame(timePerFrame, r))) {}
|
||||||
this(Array.ConvertAll(regions, r => new AnimationFrame(timePerFrame, r))) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new sprite animation that contains the given texture region arrays as frames, where each frame represents one set of texture regions.
|
/// Creates a new sprite animation that contains the given texture region arrays as frames, where each frame represents one set of texture regions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
||||||
/// <param name="regions">The texture regions that should make up this animation</param>
|
/// <param name="regions">The texture regions that should make up this animation</param>
|
||||||
public SpriteAnimation(double timePerFrame, params TextureRegion[][] regions) :
|
public SpriteAnimation(double timePerFrame, params TextureRegion[][] regions) : this(Array.ConvertAll(regions, r => new AnimationFrame(timePerFrame, r))) {}
|
||||||
this(Array.ConvertAll(regions, r => new AnimationFrame(timePerFrame, r))) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new sprite animation based on the given texture regions in rectangle-based format.
|
/// Creates a new sprite animation based on the given texture regions in rectangle-based format.
|
||||||
|
@ -122,9 +118,7 @@ namespace MLEM.Animations {
|
||||||
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
/// <param name="timePerFrame">The amount of time that each frame should last for</param>
|
||||||
/// <param name="texture">The texture that the regions should come from</param>
|
/// <param name="texture">The texture that the regions should come from</param>
|
||||||
/// <param name="regions">The texture regions that should make up this animation</param>
|
/// <param name="regions">The texture regions that should make up this animation</param>
|
||||||
public SpriteAnimation(double timePerFrame, Texture2D texture, params Rectangle[] regions) :
|
public SpriteAnimation(double timePerFrame, Texture2D texture, params Rectangle[] regions) : this(timePerFrame, Array.ConvertAll(regions, r => new TextureRegion(texture, r))) {}
|
||||||
this(timePerFrame, Array.ConvertAll(regions, r => new TextureRegion(texture, r))) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates this animation, causing <see cref="TimeIntoAnimation"/> to be increased and the <see cref="CurrentFrame"/> to be updated.
|
/// Updates this animation, causing <see cref="TimeIntoAnimation"/> to be increased and the <see cref="CurrentFrame"/> to be updated.
|
||||||
|
|
|
@ -3,16 +3,16 @@ using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
namespace MLEM.Extensions {
|
namespace MLEM.Extensions {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A set of extensions for dealing with <see cref="Color"/> objects
|
/// A set of extensions for dealing with <see cref="Color"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ColorExtensions {
|
public static class ColorExtensions {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies the alpha value from another color into this color.
|
/// Copies the alpha value from another color into this color and returns the result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The color</param>
|
/// <param name="color">The color.</param>
|
||||||
/// <param name="other">The color to copy the alpha from</param>
|
/// <param name="other">The color to copy the alpha from.</param>
|
||||||
/// <returns>The first color with the second color's alpha value</returns>
|
/// <returns>The first color with the second color's alpha value.</returns>
|
||||||
public static Color CopyAlpha(this Color color, Color other) {
|
public static Color CopyAlpha(this Color color, Color other) {
|
||||||
return color * (other.A / 255F);
|
return color * (other.A / 255F);
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,26 @@ namespace MLEM.Extensions {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an inverted version of this color.
|
/// Returns an inverted version of this color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The color to invert</param>
|
/// <param name="color">The color to invert.</param>
|
||||||
/// <returns>The inverted color</returns>
|
/// <returns>The inverted color.</returns>
|
||||||
public static Color Invert(this Color color) {
|
public static Color Invert(this Color color) {
|
||||||
return new Color(255 - color.R, 255 - color.G, 255 - color.B, color.A);
|
return new Color(255 - color.R, 255 - color.G, 255 - color.B, color.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies this color with another color and returns the result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The first color.</param>
|
||||||
|
/// <param name="other">The second color.</param>
|
||||||
|
/// <returns>The two colors multiplied together.</returns>
|
||||||
|
public static Color Multiply(this Color color, Color other) {
|
||||||
|
return new Color(color.ToVector4() * other.ToVector4());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A set of utility methods for dealing with <see cref="Color"/> objects
|
/// A set of utility methods for dealing with <see cref="Color"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ColorHelper {
|
public static class ColorHelper {
|
||||||
|
|
||||||
|
@ -37,28 +47,28 @@ namespace MLEM.Extensions {
|
||||||
/// Parses a hexadecimal number into an rgba color.
|
/// Parses a hexadecimal number into an rgba color.
|
||||||
/// The number should be in the format <c>0xaarrggbb</c>.
|
/// The number should be in the format <c>0xaarrggbb</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The number to parse</param>
|
/// <param name="value">The number to parse.</param>
|
||||||
/// <returns>The resulting color</returns>
|
/// <returns>The resulting color.</returns>
|
||||||
public static Color FromHexRgba(int value) {
|
public static Color FromHexRgba(int value) {
|
||||||
return new Color(value >> 16 & 0xFF, value >> 8 & 0xFF, value >> 0 & 0xFF, value >> 24 & 0xFF);
|
return new Color((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value >> 0) & 0xFF, (value >> 24) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a hexadecimal number into an rgb color with 100% alpha.
|
/// Parses a hexadecimal number into an rgb color with 100% alpha.
|
||||||
/// The number should be in the format <c>0xrrggbb</c>.
|
/// The number should be in the format <c>0xrrggbb</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The number to parse</param>
|
/// <param name="value">The number to parse.</param>
|
||||||
/// <returns>The resulting color</returns>
|
/// <returns>The resulting color.</returns>
|
||||||
public static Color FromHexRgb(int value) {
|
public static Color FromHexRgb(int value) {
|
||||||
return new Color(value >> 16 & 0xFF, value >> 8 & 0xFF, value >> 0 & 0xFF);
|
return new Color((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value >> 0) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a hexadecimal string into a color.
|
/// Parses a hexadecimal string into a color.
|
||||||
/// The string can either be formatted as RRGGBB or AARRGGBB and can optionally start with a <c>#</c>.
|
/// The string can either be formatted as RRGGBB or AARRGGBB and can optionally start with a <c>#</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The string to parse</param>
|
/// <param name="value">The string to parse.</param>
|
||||||
/// <returns>The resulting color</returns>
|
/// <returns>The resulting color.</returns>
|
||||||
public static Color FromHexString(string value) {
|
public static Color FromHexString(string value) {
|
||||||
if (value.StartsWith("#"))
|
if (value.StartsWith("#"))
|
||||||
value = value.Substring(1);
|
value = value.Substring(1);
|
||||||
|
|
|
@ -41,5 +41,18 @@ namespace MLEM.Extensions {
|
||||||
throw new IndexOutOfRangeException();
|
throw new IndexOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="GetRandomWeightedEntry{T}(System.Random,System.Collections.Generic.IList{T},System.Func{T,int})"/>
|
||||||
|
public static T GetRandomWeightedEntry<T>(this Random random, IList<T> entries, Func<T, float> weightFunc) {
|
||||||
|
var totalWeight = entries.Sum(weightFunc);
|
||||||
|
var goalWeight = random.NextDouble() * totalWeight;
|
||||||
|
var currWeight = 0F;
|
||||||
|
foreach (var entry in entries) {
|
||||||
|
currWeight += weightFunc(entry);
|
||||||
|
if (currWeight >= goalWeight)
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,10 @@ namespace MLEM.Font {
|
||||||
/// This is a character that isn't drawn, but has the same width as <see cref="LineHeight"/>.
|
/// This is a character that isn't drawn, but has the same width as <see cref="LineHeight"/>.
|
||||||
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/>.
|
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const char OneEmSpace = '\u2003';
|
public const char Emsp = '\u2003';
|
||||||
|
/// <inheritdoc cref="Emsp"/>
|
||||||
|
[Obsolete("Use the Emsp field instead.")]
|
||||||
|
public const char OneEmSpace = Emsp;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This field holds the unicode representation of a non-breaking space.
|
/// This field holds the unicode representation of a non-breaking space.
|
||||||
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/>.
|
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/>.
|
||||||
|
@ -26,7 +29,7 @@ namespace MLEM.Font {
|
||||||
public const char Nbsp = '\u00A0';
|
public const char Nbsp = '\u00A0';
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This field holds the unicode representation of a zero-width space.
|
/// This field holds the unicode representation of a zero-width space.
|
||||||
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations and string splitting, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/> and <see cref="SplitString"/>.
|
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations and string splitting, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/> and <see cref="SplitString(string,float,float)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const char Zwsp = '\u200B';
|
public const char Zwsp = '\u200B';
|
||||||
|
|
||||||
|
@ -48,17 +51,35 @@ namespace MLEM.Font {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Measures the width of the given character with the default scale for use in <see cref="MeasureString(string,bool)"/>.
|
/// Measures the width of the given character with the default scale for use in <see cref="MeasureString(string,bool)"/>.
|
||||||
/// Note that this method does not support <see cref="Nbsp"/>, <see cref="Zwsp"/> and <see cref="OneEmSpace"/> for most generic fonts, which is why <see cref="MeasureString(string,bool)"/> should be used even for single characters.
|
/// Note that this method does not support <see cref="Nbsp"/>, <see cref="Zwsp"/> and <see cref="Emsp"/> for most generic fonts, which is why <see cref="MeasureString(string,bool)"/> should be used even for single characters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="c">The character whose width to calculate</param>
|
/// <param name="c">The character whose width to calculate</param>
|
||||||
/// <returns>The width of the given character with the default scale</returns>
|
/// <returns>The width of the given character with the default scale</returns>
|
||||||
protected abstract float MeasureChar(char c);
|
protected abstract float MeasureChar(char c);
|
||||||
|
|
||||||
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
/// <summary>
|
||||||
public abstract void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
|
/// Draws the given character with the given data for use in <see cref="DrawString(Microsoft.Xna.Framework.Graphics.SpriteBatch,System.Text.StringBuilder,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Color,float,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Vector2,Microsoft.Xna.Framework.Graphics.SpriteEffects,float)"/>.
|
||||||
|
/// Note that this method is only called internally.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="batch">The sprite batch to draw with.</param>
|
||||||
|
/// <param name="cString">A string representation of the character which will be drawn.</param>
|
||||||
|
/// <param name="position">The drawing location on screen.</param>
|
||||||
|
/// <param name="color">A color mask.</param>
|
||||||
|
/// <param name="rotation">A rotation of this character.</param>
|
||||||
|
/// <param name="scale">A scaling of this character.</param>
|
||||||
|
/// <param name="effects">Modificators for drawing. Can be combined.</param>
|
||||||
|
/// <param name="layerDepth">A depth of the layer of this character.</param>
|
||||||
|
protected abstract void DrawChar(SpriteBatch batch, string cString, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth);
|
||||||
|
|
||||||
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
||||||
public abstract void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
|
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
|
this.DrawString(batch, new CharSource(text), position, color, rotation, origin, scale, effects, layerDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
||||||
|
public void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
|
this.DrawString(batch, new CharSource(text), position, color, rotation, origin, scale, effects, layerDepth);
|
||||||
|
}
|
||||||
|
|
||||||
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
///<inheritdoc cref="SpriteBatch.DrawString(SpriteFont,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
||||||
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth) {
|
public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth) {
|
||||||
|
@ -82,14 +103,19 @@ namespace MLEM.Font {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Measures the width of the given string when drawn with this font's underlying font.
|
/// Measures the width of the given string when drawn with this font's underlying font.
|
||||||
/// This method uses <see cref="MeasureChar"/> internally to calculate the size of known characters and calculates additional characters like <see cref="Nbsp"/>, <see cref="Zwsp"/> and <see cref="OneEmSpace"/>.
|
/// This method uses <see cref="MeasureChar"/> internally to calculate the size of known characters and calculates additional characters like <see cref="Nbsp"/>, <see cref="Zwsp"/> and <see cref="Emsp"/>.
|
||||||
/// If the text contains newline characters (\n), the size returned will represent a rectangle that encompasses the width of the longest line and the string's full height.
|
/// If the text contains newline characters (\n), the size returned will represent a rectangle that encompasses the width of the longest line and the string's full height.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The text whose size to calculate</param>
|
/// <param name="text">The text whose size to calculate</param>
|
||||||
/// <param name="ignoreTrailingSpaces">Whether trailing whitespace should be ignored in the returned size, causing the end of each line to be effectively trimmed</param>
|
/// <param name="ignoreTrailingSpaces">Whether trailing whitespace should be ignored in the returned size, causing the end of each line to be effectively trimmed</param>
|
||||||
/// <returns>The size of the string when drawn with this font</returns>
|
/// <returns>The size of the string when drawn with this font</returns>
|
||||||
public Vector2 MeasureString(string text, bool ignoreTrailingSpaces = false) {
|
public Vector2 MeasureString(string text, bool ignoreTrailingSpaces = false) {
|
||||||
return this.MeasureString(text, ignoreTrailingSpaces, null);
|
return this.MeasureString(new CharSource(text), ignoreTrailingSpaces, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="MeasureString(string,bool)"/>
|
||||||
|
public Vector2 MeasureString(StringBuilder text, bool ignoreTrailingSpaces = false) {
|
||||||
|
return this.MeasureString(new CharSource(text), ignoreTrailingSpaces, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -103,7 +129,12 @@ namespace MLEM.Font {
|
||||||
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
||||||
/// <returns>The truncated string, or the same string if it is shorter than the maximum width</returns>
|
/// <returns>The truncated string, or the same string if it is shorter than the maximum width</returns>
|
||||||
public string TruncateString(string text, float width, float scale, bool fromBack = false, string ellipsis = "") {
|
public string TruncateString(string text, float width, float scale, bool fromBack = false, string ellipsis = "") {
|
||||||
return this.TruncateString(text, width, scale, fromBack, ellipsis, null);
|
return this.TruncateString(new CharSource(text), width, scale, fromBack, ellipsis, null).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="TruncateString(string,float,float,bool,string)"/>
|
||||||
|
public StringBuilder TruncateString(StringBuilder text, float width, float scale, bool fromBack = false, string ellipsis = "") {
|
||||||
|
return this.TruncateString(new CharSource(text), width, scale, fromBack, ellipsis, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -119,20 +150,30 @@ namespace MLEM.Font {
|
||||||
return string.Join("\n", this.SplitStringSeparate(text, width, scale));
|
return string.Join("\n", this.SplitStringSeparate(text, width, scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SplitString(string,float,float)"/>
|
||||||
|
public string SplitString(StringBuilder text, float width, float scale) {
|
||||||
|
return string.Join("\n", this.SplitStringSeparate(text, width, scale));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits a string to a given maximum width and returns each split section as a separate string.
|
/// Splits a string to a given maximum width and returns each split section as a separate string.
|
||||||
/// Note that existing new lines are taken into account for line length, but not split in the resulting strings.
|
/// Note that existing new lines are taken into account for line length, but not split in the resulting strings.
|
||||||
/// This method differs from <see cref="SplitString"/> in that it differentiates between pre-existing newline characters and splits due to maximum width.
|
/// This method differs from <see cref="SplitString(string,float,float)"/> in that it differentiates between pre-existing newline characters and splits due to maximum width.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The text to split into multiple lines</param>
|
/// <param name="text">The text to split into multiple lines</param>
|
||||||
/// <param name="width">The maximum width that each line should have</param>
|
/// <param name="width">The maximum width that each line should have</param>
|
||||||
/// <param name="scale">The scale to use for width measurements</param>
|
/// <param name="scale">The scale to use for width measurements</param>
|
||||||
/// <returns>The split string as an enumerable of split sections</returns>
|
/// <returns>The split string as an enumerable of split sections</returns>
|
||||||
public IEnumerable<string> SplitStringSeparate(string text, float width, float scale) {
|
public IEnumerable<string> SplitStringSeparate(string text, float width, float scale) {
|
||||||
return this.SplitStringSeparate(text, width, scale, null);
|
return this.SplitStringSeparate(new CharSource(text), width, scale, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vector2 MeasureString(string text, bool ignoreTrailingSpaces, Func<int, GenericFont> fontFunction) {
|
/// <inheritdoc cref="SplitStringSeparate(string,float,float)"/>
|
||||||
|
public IEnumerable<string> SplitStringSeparate(StringBuilder text, float width, float scale) {
|
||||||
|
return this.SplitStringSeparate(new CharSource(text), width, scale, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Vector2 MeasureString(CharSource text, bool ignoreTrailingSpaces, Func<int, GenericFont> fontFunction) {
|
||||||
var size = Vector2.Zero;
|
var size = Vector2.Zero;
|
||||||
if (text.Length <= 0)
|
if (text.Length <= 0)
|
||||||
return size;
|
return size;
|
||||||
|
@ -144,7 +185,7 @@ namespace MLEM.Font {
|
||||||
xOffset = 0;
|
xOffset = 0;
|
||||||
size.Y += this.LineHeight;
|
size.Y += this.LineHeight;
|
||||||
break;
|
break;
|
||||||
case OneEmSpace:
|
case Emsp:
|
||||||
xOffset += this.LineHeight;
|
xOffset += this.LineHeight;
|
||||||
break;
|
break;
|
||||||
case Nbsp:
|
case Nbsp:
|
||||||
|
@ -174,7 +215,7 @@ namespace MLEM.Font {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string TruncateString(string text, float width, float scale, bool fromBack, string ellipsis, Func<int, GenericFont> fontFunction) {
|
internal StringBuilder TruncateString(CharSource text, float width, float scale, bool fromBack, string ellipsis, Func<int, GenericFont> fontFunction) {
|
||||||
var total = new StringBuilder();
|
var total = new StringBuilder();
|
||||||
for (var i = 0; i < text.Length; i++) {
|
for (var i = 0; i < text.Length; i++) {
|
||||||
if (fromBack) {
|
if (fromBack) {
|
||||||
|
@ -186,16 +227,16 @@ namespace MLEM.Font {
|
||||||
var font = fontFunction?.Invoke(i) ?? this;
|
var font = fontFunction?.Invoke(i) ?? this;
|
||||||
if (font.MeasureString(total + ellipsis).X * scale >= width) {
|
if (font.MeasureString(total + ellipsis).X * scale >= width) {
|
||||||
if (fromBack) {
|
if (fromBack) {
|
||||||
return total.Remove(0, 1).Insert(0, ellipsis).ToString();
|
return total.Remove(0, 1).Insert(0, ellipsis);
|
||||||
} else {
|
} else {
|
||||||
return total.Remove(total.Length - 1, 1).Append(ellipsis).ToString();
|
return total.Remove(total.Length - 1, 1).Append(ellipsis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total.ToString();
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<string> SplitStringSeparate(string text, float width, float scale, Func<int, GenericFont> fontFunction) {
|
internal IEnumerable<string> SplitStringSeparate(CharSource text, float width, float scale, Func<int, GenericFont> fontFunction) {
|
||||||
var currWidth = 0F;
|
var currWidth = 0F;
|
||||||
var lastSpaceIndex = -1;
|
var lastSpaceIndex = -1;
|
||||||
var widthSinceLastSpace = 0F;
|
var widthSinceLastSpace = 0F;
|
||||||
|
@ -211,7 +252,7 @@ namespace MLEM.Font {
|
||||||
} else {
|
} else {
|
||||||
var font = fontFunction?.Invoke(i) ?? this;
|
var font = fontFunction?.Invoke(i) ?? this;
|
||||||
var cWidth = font.MeasureString(c.ToCachedString()).X * scale;
|
var cWidth = font.MeasureString(c.ToCachedString()).X * scale;
|
||||||
if (c == ' ' || c == OneEmSpace || c == Zwsp) {
|
if (c == ' ' || c == Emsp || c == Zwsp) {
|
||||||
// remember the location of this (breaking!) space
|
// remember the location of this (breaking!) space
|
||||||
lastSpaceIndex = curr.Length;
|
lastSpaceIndex = curr.Length;
|
||||||
widthSinceLastSpace = 0;
|
widthSinceLastSpace = 0;
|
||||||
|
@ -243,7 +284,64 @@ namespace MLEM.Font {
|
||||||
yield return curr.ToString();
|
yield return curr.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsTrailingSpace(string s, int index) {
|
private void DrawString(SpriteBatch batch, CharSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
|
var (flipX, flipY) = Vector2.Zero;
|
||||||
|
var flippedV = (effects & SpriteEffects.FlipVertically) != 0;
|
||||||
|
var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0;
|
||||||
|
if (flippedV || flippedH) {
|
||||||
|
var (w, h) = this.MeasureString(text, false, null);
|
||||||
|
if (flippedH) {
|
||||||
|
origin.X *= -1;
|
||||||
|
flipX = -w;
|
||||||
|
}
|
||||||
|
if (flippedV) {
|
||||||
|
origin.Y *= -1;
|
||||||
|
flipY = this.LineHeight - h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var trans = Matrix.Identity;
|
||||||
|
if (rotation == 0) {
|
||||||
|
trans.M11 = flippedH ? -scale.X : scale.X;
|
||||||
|
trans.M22 = flippedV ? -scale.Y : scale.Y;
|
||||||
|
trans.M41 = (flipX - origin.X) * trans.M11 + position.X;
|
||||||
|
trans.M42 = (flipY - origin.Y) * trans.M22 + position.Y;
|
||||||
|
} else {
|
||||||
|
var sin = (float) Math.Sin(rotation);
|
||||||
|
var cos = (float) Math.Cos(rotation);
|
||||||
|
trans.M11 = (flippedH ? -scale.X : scale.X) * cos;
|
||||||
|
trans.M12 = (flippedH ? -scale.X : scale.X) * sin;
|
||||||
|
trans.M21 = (flippedV ? -scale.Y : scale.Y) * -sin;
|
||||||
|
trans.M22 = (flippedV ? -scale.Y : scale.Y) * cos;
|
||||||
|
trans.M41 = (flipX - origin.X) * trans.M11 + (flipY - origin.Y) * trans.M21 + position.X;
|
||||||
|
trans.M42 = (flipX - origin.X) * trans.M12 + (flipY - origin.Y) * trans.M22 + position.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = Vector2.Zero;
|
||||||
|
for (var i = 0; i < text.Length; i++) {
|
||||||
|
var c = text[i];
|
||||||
|
if (c == '\n') {
|
||||||
|
offset.X = 0;
|
||||||
|
offset.Y += this.LineHeight;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cString = c.ToCachedString();
|
||||||
|
var (cW, cH) = this.MeasureString(cString);
|
||||||
|
|
||||||
|
var charPos = offset;
|
||||||
|
if (flippedH)
|
||||||
|
charPos.X += cW;
|
||||||
|
if (flippedV)
|
||||||
|
charPos.Y += cH - this.LineHeight;
|
||||||
|
Vector2.Transform(ref charPos, ref trans, out charPos);
|
||||||
|
|
||||||
|
this.DrawChar(batch, cString, charPos, color, rotation, scale, effects, layerDepth);
|
||||||
|
offset.X += cW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsTrailingSpace(CharSource s, int index) {
|
||||||
for (var i = index + 1; i < s.Length; i++) {
|
for (var i = index + 1; i < s.Length; i++) {
|
||||||
if (s[i] != ' ')
|
if (s[i] != ' ')
|
||||||
return false;
|
return false;
|
||||||
|
@ -251,5 +349,25 @@ namespace MLEM.Font {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal readonly struct CharSource {
|
||||||
|
|
||||||
|
private readonly string strg;
|
||||||
|
private readonly StringBuilder builder;
|
||||||
|
|
||||||
|
public int Length => this.strg?.Length ?? this.builder.Length;
|
||||||
|
public char this[int index] => this.strg?[index] ?? this.builder[index];
|
||||||
|
|
||||||
|
public CharSource(string strg) {
|
||||||
|
this.strg = strg;
|
||||||
|
this.builder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSource(StringBuilder builder) {
|
||||||
|
this.strg = null;
|
||||||
|
this.builder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
|
@ -37,14 +36,9 @@ namespace MLEM.Font {
|
||||||
return this.Font.MeasureString(c.ToCachedString()).X;
|
return this.Font.MeasureString(c.ToCachedString()).X;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc />
|
||||||
public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
protected override void DrawChar(SpriteBatch batch, string cString, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
||||||
batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth);
|
batch.DrawString(this.Font, cString, position, color, rotation, Vector2.Zero, scale, effects, layerDepth);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) {
|
|
||||||
batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpriteFont SetDefaults(SpriteFont font) {
|
private static SpriteFont SetDefaults(SpriteFont font) {
|
||||||
|
|
|
@ -5,8 +5,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
public class AnimatedCode : Code {
|
public class AnimatedCode : Code {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnimatedCode(Match match, Regex regex) : base(match, regex) {
|
public AnimatedCode(Match match, Regex regex) : base(match, regex) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool EndsHere(Code other) {
|
public override bool EndsHere(Code other) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
@ -20,9 +21,10 @@ namespace MLEM.Formatting.Codes {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Match Match;
|
public readonly Match Match;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The token that this formatting code is a part of
|
/// The tokens that this formatting code is a part of.
|
||||||
|
/// Note that this array only has multiple entries if additional tokens have to be started while this code is still applied.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Token Token { get; internal set; }
|
public IList<Token> Tokens { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new formatting code based on a formatting code regex and its match.
|
/// Creates a new formatting code based on a formatting code regex and its match.
|
||||||
|
@ -58,8 +60,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
/// Update this formatting code's animations etc.
|
/// Update this formatting code's animations etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The game's time</param>
|
/// <param name="time">The game's time</param>
|
||||||
public virtual void Update(GameTime time) {
|
public virtual void Update(GameTime time) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the string that this formatting code should be replaced with.
|
/// Returns the string that this formatting code should be replaced with.
|
||||||
|
@ -72,13 +73,12 @@ namespace MLEM.Formatting.Codes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Formatting.Token.DrawCharacter"/>
|
/// <inheritdoc cref="Formatting.Token.DrawCharacter"/>
|
||||||
public virtual bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
public virtual bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Formatting.Token.DrawSelf"/>
|
/// <inheritdoc cref="Formatting.Token.DrawSelf"/>
|
||||||
public virtual void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
public virtual void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 pos, GenericFont font, Color color, float scale, float depth) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new formatting code from the given regex and regex match.
|
/// Creates a new formatting code from the given regex and regex match.
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string GetReplacementString(GenericFont font) {
|
public override string GetReplacementString(GenericFont font) {
|
||||||
return GenericFont.OneEmSpace.ToCachedString();
|
return GenericFont.Emsp.ToCachedString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -36,7 +36,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
public override void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||||
var actualColor = this.copyTextColor ? color : Color.White.CopyAlpha(color);
|
var actualColor = this.copyTextColor ? color : Color.White.CopyAlpha(color);
|
||||||
batch.Draw(this.image.CurrentRegion, new RectangleF(pos, new Vector2(font.LineHeight * scale)), actualColor);
|
batch.Draw(this.image.CurrentRegion, new RectangleF(pos, new Vector2(font.LineHeight * scale)), actualColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,12 @@ namespace MLEM.Formatting.Codes {
|
||||||
public class LinkCode : UnderlineCode {
|
public class LinkCode : UnderlineCode {
|
||||||
|
|
||||||
private readonly Func<Token, bool> isSelected;
|
private readonly Func<Token, bool> isSelected;
|
||||||
|
private readonly Color? color;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public LinkCode(Match match, Regex regex, float thickness, float yOffset, Func<Token, bool> isSelected) : base(match, regex, thickness, yOffset) {
|
public LinkCode(Match match, Regex regex, float thickness, float yOffset, Func<Token, bool> isSelected, Color? color = null) : base(match, regex, thickness, yOffset) {
|
||||||
this.isSelected = isSelected;
|
this.isSelected = isSelected;
|
||||||
|
this.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -20,13 +22,22 @@ namespace MLEM.Formatting.Codes {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if this code is currently selected</returns>
|
/// <returns>True if this code is currently selected</returns>
|
||||||
public virtual bool IsSelected() {
|
public virtual bool IsSelected() {
|
||||||
return this.isSelected(this.Token);
|
foreach (var token in this.Tokens) {
|
||||||
|
if (this.isSelected(token))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
public override Color? GetColor(Color defaultPick) {
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||||
// since we inherit from UnderlineCode, we can just call base if selected
|
// since we inherit from UnderlineCode, we can just call base if selected
|
||||||
return this.IsSelected() && base.DrawCharacter(time, batch, c, cString, indexInToken, ref pos, font, ref color, ref scale, depth);
|
return this.IsSelected() && base.DrawCharacter(time, batch, c, cString, token, indexInToken, ref pos, font, ref color, ref scale, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
public class ResetFormattingCode : Code {
|
public class ResetFormattingCode : Code {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ResetFormattingCode(Match match, Regex regex) : base(match, regex) {
|
public ResetFormattingCode(Match match, Regex regex) : base(match, regex) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool EndsHere(Code other) {
|
public override bool EndsHere(Code other) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace MLEM.Formatting.Codes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||||
font.DrawString(batch, cString, pos + this.offset * scale, this.color.CopyAlpha(color), 0, Vector2.Zero, scale, SpriteEffects.None, depth);
|
font.DrawString(batch, cString, pos + this.offset * scale, this.color.CopyAlpha(color), 0, Vector2.Zero, scale, SpriteEffects.None, depth);
|
||||||
// we return false since we still want regular drawing to occur
|
// we return false since we still want regular drawing to occur
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,9 +19,9 @@ namespace MLEM.Formatting.Codes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||||
// don't underline spaces at the end of lines
|
// don't underline spaces at the end of lines
|
||||||
if (c == ' ' && this.Token.DisplayString.Length > indexInToken + 1 && this.Token.DisplayString[indexInToken + 1] == '\n')
|
if (c == ' ' && token.DisplayString.Length > indexInToken + 1 && token.DisplayString[indexInToken + 1] == '\n')
|
||||||
return false;
|
return false;
|
||||||
var (w, h) = font.MeasureString(cString) * scale;
|
var (w, h) = font.MeasureString(cString) * scale;
|
||||||
var t = h * this.thickness;
|
var t = h * this.thickness;
|
||||||
|
|
|
@ -28,8 +28,8 @@ namespace MLEM.Formatting.Codes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||||
var offset = new Vector2(0, (float) Math.Sin(this.Token.Index + indexInToken + this.TimeIntoAnimation.TotalSeconds * this.modifier) * font.LineHeight * this.heightModifier * scale);
|
var offset = new Vector2(0, (float) Math.Sin(token.Index + indexInToken + this.TimeIntoAnimation.TotalSeconds * this.modifier) * font.LineHeight * this.heightModifier * scale);
|
||||||
pos += offset;
|
pos += offset;
|
||||||
// we return false since we still want regular drawing to occur, we just changed the position
|
// we return false since we still want regular drawing to occur, we just changed the position
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -50,9 +50,6 @@ namespace MLEM.Formatting {
|
||||||
this.RawIndex = rawIndex;
|
this.RawIndex = rawIndex;
|
||||||
this.Substring = substring;
|
this.Substring = substring;
|
||||||
this.RawSubstring = rawSubstring;
|
this.RawSubstring = rawSubstring;
|
||||||
|
|
||||||
foreach (var code in appliedCodes)
|
|
||||||
code.Token = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -96,7 +93,7 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="depth">The depth to draw at</param>
|
/// <param name="depth">The depth to draw at</param>
|
||||||
public void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
public void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||||
foreach (var code in this.AppliedCodes)
|
foreach (var code in this.AppliedCodes)
|
||||||
code.DrawSelf(time, batch, pos, font, color, scale, depth);
|
code.DrawSelf(time, batch, this, pos, font, color, scale, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -114,7 +111,7 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="depth">The depth to draw at</param>
|
/// <param name="depth">The depth to draw at</param>
|
||||||
public void DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
public void DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||||
foreach (var code in this.AppliedCodes) {
|
foreach (var code in this.AppliedCodes) {
|
||||||
if (code.DrawCharacter(time, batch, c, cString, indexInToken, ref pos, font, ref color, ref scale, depth))
|
if (code.DrawCharacter(time, batch, c, cString, this, indexInToken, ref pos, font, ref color, ref scale, depth))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
@ -7,6 +8,7 @@ using MLEM.Extensions;
|
||||||
using MLEM.Font;
|
using MLEM.Font;
|
||||||
using MLEM.Formatting.Codes;
|
using MLEM.Formatting.Codes;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
|
using static MLEM.Font.GenericFont;
|
||||||
|
|
||||||
namespace MLEM.Formatting {
|
namespace MLEM.Formatting {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -43,15 +45,19 @@ namespace MLEM.Formatting {
|
||||||
this.RawString = rawString;
|
this.RawString = rawString;
|
||||||
this.String = strg;
|
this.String = strg;
|
||||||
this.Tokens = tokens;
|
this.Tokens = tokens;
|
||||||
|
|
||||||
// since a code can be present in multiple tokens, we use Distinct here
|
// since a code can be present in multiple tokens, we use Distinct here
|
||||||
this.AllCodes = tokens.SelectMany(t => t.AppliedCodes).Distinct().ToArray();
|
this.AllCodes = tokens.SelectMany(t => t.AppliedCodes).Distinct().ToArray();
|
||||||
|
// TODO this can probably be optimized by keeping track of a code's tokens while tokenizing
|
||||||
|
foreach (var code in this.AllCodes)
|
||||||
|
code.Tokens = new ReadOnlyCollection<Token>(this.Tokens.Where(t => t.AppliedCodes.Contains(code)).ToList());
|
||||||
|
|
||||||
this.RecalculateTokenData(font, alignment);
|
this.RecalculateTokenData(font, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits this tokenized string, inserting newline characters if the width of the string is bigger than the maximum width.
|
/// Splits this tokenized string, inserting newline characters if the width of the string is bigger than the maximum width.
|
||||||
/// Note that a tokenized string can be re-split without losing any of its actual data, as this operation merely modifies the <see cref="DisplayString"/>.
|
/// Note that a tokenized string can be re-split without losing any of its actual data, as this operation merely modifies the <see cref="DisplayString"/>.
|
||||||
/// <seealso cref="GenericFont.SplitString"/>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="font">The font to use for width calculations</param>
|
/// <param name="font">The font to use for width calculations</param>
|
||||||
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
/// <param name="width">The maximum width, in display pixels based on the font and scale</param>
|
||||||
|
@ -59,7 +65,7 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
||||||
public void Split(GenericFont font, float width, float scale, TextAlignment alignment = TextAlignment.Left) {
|
public void Split(GenericFont font, float width, float scale, TextAlignment alignment = TextAlignment.Left) {
|
||||||
// a split string has the same character count as the input string but with newline characters added
|
// a split string has the same character count as the input string but with newline characters added
|
||||||
this.modifiedString = string.Join("\n", font.SplitStringSeparate(this.String, width, scale, i => this.GetFontForIndex(font, i)));
|
this.modifiedString = string.Join("\n", font.SplitStringSeparate(new CharSource(this.String), width, scale, i => this.GetFontForIndex(font, i)));
|
||||||
this.StoreModifiedSubstrings(font, alignment);
|
this.StoreModifiedSubstrings(font, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +80,13 @@ namespace MLEM.Formatting {
|
||||||
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
/// <param name="ellipsis">The characters to add to the end of the string if it is too long</param>
|
||||||
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
/// <param name="alignment">The text alignment that should be used for width calculations</param>
|
||||||
public void Truncate(GenericFont font, float width, float scale, string ellipsis = "", TextAlignment alignment = TextAlignment.Left) {
|
public void Truncate(GenericFont font, float width, float scale, string ellipsis = "", TextAlignment alignment = TextAlignment.Left) {
|
||||||
this.modifiedString = font.TruncateString(this.String, width, scale, false, ellipsis, i => this.GetFontForIndex(font, i));
|
this.modifiedString = font.TruncateString(new CharSource(this.String), width, scale, false, ellipsis, i => this.GetFontForIndex(font, i)).ToString();
|
||||||
this.StoreModifiedSubstrings(font, alignment);
|
this.StoreModifiedSubstrings(font, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GenericFont.MeasureString(string,bool)"/>
|
/// <inheritdoc cref="GenericFont.MeasureString(string,bool)"/>
|
||||||
public Vector2 Measure(GenericFont font) {
|
public Vector2 Measure(GenericFont font) {
|
||||||
return font.MeasureString(this.DisplayString, false, i => this.GetFontForIndex(font, i));
|
return font.MeasureString(new CharSource(this.DisplayString), false, i => this.GetFontForIndex(font, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -117,17 +123,20 @@ namespace MLEM.Formatting {
|
||||||
var token = this.Tokens[t];
|
var token = this.Tokens[t];
|
||||||
var drawFont = token.GetFont(font);
|
var drawFont = token.GetFont(font);
|
||||||
var drawColor = token.GetColor(color);
|
var drawColor = token.GetColor(color);
|
||||||
|
|
||||||
|
var indexInToken = 0;
|
||||||
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
|
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
|
||||||
var line = token.SplitDisplayString[l];
|
foreach (var c in token.SplitDisplayString[l]) {
|
||||||
for (var i = 0; i < line.Length; i++) {
|
|
||||||
var c = line[i];
|
|
||||||
if (l == 0 && i == 0)
|
|
||||||
token.DrawSelf(time, batch, pos + innerOffset, drawFont, color, scale, depth);
|
|
||||||
|
|
||||||
var cString = c.ToCachedString();
|
var cString = c.ToCachedString();
|
||||||
token.DrawCharacter(time, batch, c, cString, i, pos + innerOffset, drawFont, drawColor, scale, depth);
|
|
||||||
|
if (indexInToken == 0)
|
||||||
|
token.DrawSelf(time, batch, pos + innerOffset, drawFont, color, scale, depth);
|
||||||
|
token.DrawCharacter(time, batch, c, cString, indexInToken, pos + innerOffset, drawFont, drawColor, scale, depth);
|
||||||
|
|
||||||
innerOffset.X += drawFont.MeasureString(cString).X * scale;
|
innerOffset.X += drawFont.MeasureString(cString).X * scale;
|
||||||
|
indexInToken++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only split at a new line, not between tokens!
|
// only split at a new line, not between tokens!
|
||||||
if (l < token.SplitDisplayString.Length - 1) {
|
if (l < token.SplitDisplayString.Length - 1) {
|
||||||
innerOffset.X = token.InnerOffsets[l] * scale;
|
innerOffset.X = token.InnerOffsets[l] * scale;
|
||||||
|
|
|
@ -367,18 +367,38 @@ namespace MLEM.Graphics {
|
||||||
|
|
||||||
private Item Add(Texture2D texture, Vector2 pos, Vector2 offset, Vector2 size, float sin, float cos, Color color, Vector2 texTl, Vector2 texBr, float depth) {
|
private Item Add(Texture2D texture, Vector2 pos, Vector2 offset, Vector2 size, float sin, float cos, Color color, Vector2 texTl, Vector2 texBr, float depth) {
|
||||||
return this.Add(texture, depth,
|
return this.Add(texture, depth,
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + offset.X * cos - offset.Y * sin, pos.Y + offset.X * sin + offset.Y * cos, depth), color, texTl),
|
new VertexPositionColorTexture(new Vector3(
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + (offset.X + size.X) * cos - offset.Y * sin, pos.Y + (offset.X + size.X) + offset.Y * cos, depth), color, new Vector2(texBr.X, texTl.Y)),
|
pos.X + offset.X * cos - offset.Y * sin,
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + offset.X * cos - (offset.Y + size.Y) * sin, pos.Y + offset.X * sin + (offset.Y + size.Y) * cos, depth), color, new Vector2(texTl.X, texBr.Y)),
|
pos.Y + offset.X * sin + offset.Y * cos, depth),
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + (offset.X + size.X) * cos - (offset.Y + size.Y) * sin, pos.Y + (offset.X + size.X) * sin + (offset.Y + size.Y) * cos, depth), color, texBr));
|
color, texTl),
|
||||||
|
new VertexPositionColorTexture(new Vector3(
|
||||||
|
pos.X + (offset.X + size.X) * cos - offset.Y * sin,
|
||||||
|
pos.Y + (offset.X + size.X) * sin + offset.Y * cos, depth),
|
||||||
|
color, new Vector2(texBr.X, texTl.Y)),
|
||||||
|
new VertexPositionColorTexture(new Vector3(
|
||||||
|
pos.X + offset.X * cos - (offset.Y + size.Y) * sin,
|
||||||
|
pos.Y + offset.X * sin + (offset.Y + size.Y) * cos, depth),
|
||||||
|
color, new Vector2(texTl.X, texBr.Y)),
|
||||||
|
new VertexPositionColorTexture(new Vector3(
|
||||||
|
pos.X + (offset.X + size.X) * cos - (offset.Y + size.Y) * sin,
|
||||||
|
pos.Y + (offset.X + size.X) * sin + (offset.Y + size.Y) * cos, depth),
|
||||||
|
color, texBr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Item Add(Texture2D texture, Vector2 pos, Vector2 size, Color color, Vector2 texTl, Vector2 texBr, float depth) {
|
private Item Add(Texture2D texture, Vector2 pos, Vector2 size, Color color, Vector2 texTl, Vector2 texBr, float depth) {
|
||||||
return this.Add(texture, depth,
|
return this.Add(texture, depth,
|
||||||
new VertexPositionColorTexture(new Vector3(pos, depth), color, texTl),
|
new VertexPositionColorTexture(
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + size.X, pos.Y, depth), color, new Vector2(texBr.X, texTl.Y)),
|
new Vector3(pos, depth),
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X, pos.Y + size.Y, depth), color, new Vector2(texTl.X, texBr.Y)),
|
color, texTl),
|
||||||
new VertexPositionColorTexture(new Vector3(pos.X + size.X, pos.Y + size.Y, depth), color, texBr));
|
new VertexPositionColorTexture(
|
||||||
|
new Vector3(pos.X + size.X, pos.Y, depth),
|
||||||
|
color, new Vector2(texBr.X, texTl.Y)),
|
||||||
|
new VertexPositionColorTexture(
|
||||||
|
new Vector3(pos.X, pos.Y + size.Y, depth),
|
||||||
|
color, new Vector2(texTl.X, texBr.Y)),
|
||||||
|
new VertexPositionColorTexture(
|
||||||
|
new Vector3(pos.X + size.X, pos.Y + size.Y, depth),
|
||||||
|
color, texBr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Item Add(Texture2D texture, float depth, VertexPositionColorTexture tl, VertexPositionColorTexture tr, VertexPositionColorTexture bl, VertexPositionColorTexture br) {
|
private Item Add(Texture2D texture, float depth, VertexPositionColorTexture tl, VertexPositionColorTexture tr, VertexPositionColorTexture bl, VertexPositionColorTexture br) {
|
||||||
|
|
45
MLEM/Input/GamepadExtensions.cs
Normal file
45
MLEM/Input/GamepadExtensions.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
namespace MLEM.Input {
|
||||||
|
/// <summary>
|
||||||
|
/// A set of extension methods for dealing with <see cref="GamePad"/>, <see cref="GamePadState"/> and <see cref="Buttons"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class GamepadExtensions {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the given <see cref="Buttons"/>'s value as an analog value between 0 and 1, where 1 is fully down and 0 is not down at all.
|
||||||
|
/// For non-analog buttons, like <see cref="Buttons.X"/> or <see cref="Buttons.Start"/>, only 0 and 1 will be returned and no inbetween values are possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The gamepad state to query.</param>
|
||||||
|
/// <param name="button">The button to query.</param>
|
||||||
|
/// <returns>The button's state as an analog value.</returns>
|
||||||
|
public static float GetAnalogValue(this GamePadState state, Buttons button) {
|
||||||
|
switch (button) {
|
||||||
|
case Buttons.LeftThumbstickDown:
|
||||||
|
return -MathHelper.Clamp(state.ThumbSticks.Left.Y, -1, 0);
|
||||||
|
case Buttons.LeftThumbstickUp:
|
||||||
|
return MathHelper.Clamp(state.ThumbSticks.Left.Y, 0, 1);
|
||||||
|
case Buttons.LeftThumbstickLeft:
|
||||||
|
return -MathHelper.Clamp(state.ThumbSticks.Left.X, -1, 0);
|
||||||
|
case Buttons.LeftThumbstickRight:
|
||||||
|
return MathHelper.Clamp(state.ThumbSticks.Left.X, 0, 1);
|
||||||
|
case Buttons.RightTrigger:
|
||||||
|
return state.Triggers.Right;
|
||||||
|
case Buttons.LeftTrigger:
|
||||||
|
return state.Triggers.Left;
|
||||||
|
case Buttons.RightThumbstickDown:
|
||||||
|
return -MathHelper.Clamp(state.ThumbSticks.Right.Y, -1, 0);
|
||||||
|
case Buttons.RightThumbstickUp:
|
||||||
|
return MathHelper.Clamp(state.ThumbSticks.Right.Y, 0, 1);
|
||||||
|
case Buttons.RightThumbstickLeft:
|
||||||
|
return -MathHelper.Clamp(state.ThumbSticks.Right.X, -1, 0);
|
||||||
|
case Buttons.RightThumbstickRight:
|
||||||
|
return MathHelper.Clamp(state.ThumbSticks.Right.X, 0, 1);
|
||||||
|
default:
|
||||||
|
return state.IsButtonDown(button) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ namespace MLEM.Input {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A generic input represents any kind of input key.
|
/// A generic input represents any kind of input key.
|
||||||
/// This includes <see cref="Keys"/> for keyboard keys, <see cref="MouseButton"/> for mouse buttons and <see cref="Buttons"/> for gamepad buttons.
|
/// This includes <see cref="Keys"/> for keyboard keys, <see cref="MouseButton"/> for mouse buttons and <see cref="Buttons"/> for gamepad buttons.
|
||||||
/// For creating and extracting inputs from a generic input, the implicit operators and <see cref="Type"/> can be used.
|
/// For creating and extracting inputs from a generic input, the implicit operators and <see cref="Type"/> can additionally be used.
|
||||||
/// Note that this type is serializable using <see cref="DataContractAttribute"/>.
|
/// Note that this type is serializable using <see cref="DataContractAttribute"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataContract]
|
[DataContract]
|
||||||
|
@ -20,6 +20,46 @@ namespace MLEM.Input {
|
||||||
[DataMember]
|
[DataMember]
|
||||||
private readonly int value;
|
private readonly int value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this generic input's <see cref="Keys"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/> or <see cref="InputType.None"/>.</exception>
|
||||||
|
public Keys Key {
|
||||||
|
get {
|
||||||
|
if (this.Type == InputType.None)
|
||||||
|
return Keys.None;
|
||||||
|
return this.Type == InputType.Keyboard ? (Keys) this.value : throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this generic input's <see cref="MouseButton"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Mouse"/>.</exception>
|
||||||
|
public MouseButton MouseButton => this.Type == InputType.Mouse ? (MouseButton) this.value : throw new InvalidOperationException();
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this generic input's <see cref="Buttons"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/>.</exception>
|
||||||
|
public Buttons Button => this.Type == InputType.Gamepad ? (Buttons) this.value : throw new InvalidOperationException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new generic input from the given keyboard <see cref="Keys"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key to convert.</param>
|
||||||
|
public GenericInput(Keys key) : this(InputType.Keyboard, (int) key) {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new generic input from the given <see cref="MouseButton"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="button">The button to convert.</param>
|
||||||
|
public GenericInput(MouseButton button) : this(InputType.Mouse, (int) button) {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new generic input from the given gamepad <see cref="Buttons"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="button">The button to convert.</param>
|
||||||
|
public GenericInput(Buttons button) : this(InputType.Gamepad, (int) button) {}
|
||||||
|
|
||||||
private GenericInput(InputType type, int value) {
|
private GenericInput(InputType type, int value) {
|
||||||
this.Type = type;
|
this.Type = type;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -83,10 +123,10 @@ namespace MLEM.Input {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a <see cref="Keys"/> to a generic input.
|
/// Converts a <see cref="Keys"/> to a generic input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keys">The keys to convert</param>
|
/// <param name="key">The keys to convert</param>
|
||||||
/// <returns>The resulting generic input</returns>
|
/// <returns>The resulting generic input</returns>
|
||||||
public static implicit operator GenericInput(Keys keys) {
|
public static implicit operator GenericInput(Keys key) {
|
||||||
return new GenericInput(InputType.Keyboard, (int) keys);
|
return new GenericInput(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -95,16 +135,16 @@ namespace MLEM.Input {
|
||||||
/// <param name="button">The button to convert</param>
|
/// <param name="button">The button to convert</param>
|
||||||
/// <returns>The resulting generic input</returns>
|
/// <returns>The resulting generic input</returns>
|
||||||
public static implicit operator GenericInput(MouseButton button) {
|
public static implicit operator GenericInput(MouseButton button) {
|
||||||
return new GenericInput(InputType.Mouse, (int) button);
|
return new GenericInput(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a <see cref="Buttons"/> to a generic input.
|
/// Converts a <see cref="Buttons"/> to a generic input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buttons">The buttons to convert</param>
|
/// <param name="button">The buttons to convert</param>
|
||||||
/// <returns>The resulting generic input</returns>
|
/// <returns>The resulting generic input</returns>
|
||||||
public static implicit operator GenericInput(Buttons buttons) {
|
public static implicit operator GenericInput(Buttons button) {
|
||||||
return new GenericInput(InputType.Gamepad, (int) buttons);
|
return new GenericInput(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -112,11 +152,9 @@ namespace MLEM.Input {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">The input to convert</param>
|
/// <param name="input">The input to convert</param>
|
||||||
/// <returns>The resulting keys</returns>
|
/// <returns>The resulting keys</returns>
|
||||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/> or <see cref="InputType.None"/></exception>
|
/// <exception cref="InvalidOperationException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/> or <see cref="InputType.None"/></exception>
|
||||||
public static implicit operator Keys(GenericInput input) {
|
public static implicit operator Keys(GenericInput input) {
|
||||||
if (input.Type == InputType.None)
|
return input.Key;
|
||||||
return Keys.None;
|
|
||||||
return input.Type == InputType.Keyboard ? (Keys) input.value : throw new ArgumentException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -124,9 +162,9 @@ namespace MLEM.Input {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">The input to convert</param>
|
/// <param name="input">The input to convert</param>
|
||||||
/// <returns>The resulting button</returns>
|
/// <returns>The resulting button</returns>
|
||||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Mouse"/></exception>
|
/// <exception cref="InvalidOperationException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Mouse"/></exception>
|
||||||
public static implicit operator MouseButton(GenericInput input) {
|
public static implicit operator MouseButton(GenericInput input) {
|
||||||
return input.Type == InputType.Mouse ? (MouseButton) input.value : throw new ArgumentException();
|
return input.MouseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -134,9 +172,9 @@ namespace MLEM.Input {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">The input to convert</param>
|
/// <param name="input">The input to convert</param>
|
||||||
/// <returns>The resulting buttons</returns>
|
/// <returns>The resulting buttons</returns>
|
||||||
/// <exception cref="ArgumentException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/></exception>
|
/// <exception cref="InvalidOperationException">If the given generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/></exception>
|
||||||
public static implicit operator Buttons(GenericInput input) {
|
public static implicit operator Buttons(GenericInput input) {
|
||||||
return input.Type == InputType.Gamepad ? (Buttons) input.value : throw new ArgumentException();
|
return input.Button;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using Microsoft.Xna.Framework.Input.Touch;
|
using Microsoft.Xna.Framework.Input.Touch;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
|
@ -15,78 +16,27 @@ namespace MLEM.Input {
|
||||||
public class InputHandler : GameComponent {
|
public class InputHandler : GameComponent {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the keyboard state from the last update call
|
/// Contains all of the gestures that have finished during the last update call.
|
||||||
|
/// To easily query these gestures, use <see cref="GetGesture"/> or <see cref="GetViewportGesture"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public KeyboardState LastKeyboardState { get; private set; }
|
public readonly ReadOnlyCollection<GestureSample> Gestures;
|
||||||
/// <summary>
|
|
||||||
/// Contains the current keyboard state
|
|
||||||
/// </summary>
|
|
||||||
public KeyboardState KeyboardState { get; private set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable keyboard handling for this input handler.
|
/// Set this field to false to disable keyboard handling for this input handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleKeyboard;
|
public bool HandleKeyboard;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the mouse state from the last update call
|
|
||||||
/// </summary>
|
|
||||||
public MouseState LastMouseState { get; private set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the current mouse state
|
|
||||||
/// </summary>
|
|
||||||
public MouseState MouseState { get; private set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the current position of the mouse, extracted from <see cref="MouseState"/>
|
|
||||||
/// </summary>
|
|
||||||
public Point MousePosition => this.MouseState.Position;
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the position of the mouse from the last update call, extracted from <see cref="LastMouseState"/>
|
|
||||||
/// </summary>
|
|
||||||
public Point LastMousePosition => this.LastMouseState.Position;
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the current scroll wheel value, in increments of 120
|
|
||||||
/// </summary>
|
|
||||||
public int ScrollWheel => this.MouseState.ScrollWheelValue;
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the scroll wheel value from the last update call, in increments of 120
|
|
||||||
/// </summary>
|
|
||||||
public int LastScrollWheel => this.LastMouseState.ScrollWheelValue;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable mouse handling for this input handler.
|
/// Set this field to false to disable mouse handling for this input handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleMouse;
|
public bool HandleMouse;
|
||||||
|
|
||||||
private readonly GamePadState[] lastGamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
|
||||||
private readonly GamePadState[] gamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the amount of gamepads that are currently connected.
|
|
||||||
/// This field is automatically updated in <see cref="Update()"/>
|
|
||||||
/// </summary>
|
|
||||||
public int ConnectedGamepads { get; private set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable keyboard handling for this input handler.
|
/// Set this field to false to disable keyboard handling for this input handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleGamepads;
|
public bool HandleGamepads;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the touch state from the last update call
|
|
||||||
/// </summary>
|
|
||||||
public TouchCollection LastTouchState { get; private set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the current touch state
|
|
||||||
/// </summary>
|
|
||||||
public TouchCollection TouchState { get; private set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Contains all of the gestures that have finished during the last update call.
|
|
||||||
/// To easily query these gestures, use <see cref="GetGesture"/>
|
|
||||||
/// </summary>
|
|
||||||
public readonly ReadOnlyCollection<GestureSample> Gestures;
|
|
||||||
private readonly List<GestureSample> gestures = new List<GestureSample>();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable touch handling for this input handler.
|
/// Set this field to false to disable touch handling for this input handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleTouch;
|
public bool HandleTouch;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the amount of time that has to pass before the first keyboard repeat event is triggered.
|
/// This is the amount of time that has to pass before the first keyboard repeat event is triggered.
|
||||||
/// <seealso cref="KeyRepeatRate"/>
|
/// <seealso cref="KeyRepeatRate"/>
|
||||||
|
@ -97,41 +47,106 @@ namespace MLEM.Input {
|
||||||
/// <seealso cref="KeyRepeatDelay"/>
|
/// <seealso cref="KeyRepeatDelay"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan KeyRepeatRate = TimeSpan.FromSeconds(0.05);
|
public TimeSpan KeyRepeatRate = TimeSpan.FromSeconds(0.05);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable keyboard repeat event handling.
|
/// Set this field to false to disable keyboard repeat event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleKeyboardRepeats = true;
|
public bool HandleKeyboardRepeats = true;
|
||||||
private DateTime heldKeyStart;
|
|
||||||
private DateTime lastKeyRepeat;
|
|
||||||
private bool triggerKeyRepeat;
|
|
||||||
private Keys heldKey;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to disable gamepad repeat event handling.
|
/// Set this field to false to disable gamepad repeat event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HandleGamepadRepeats = true;
|
public bool HandleGamepadRepeats = true;
|
||||||
private readonly DateTime[] heldGamepadButtonStarts = new DateTime[GamePad.MaximumGamePadCount];
|
/// <summary>
|
||||||
private readonly DateTime[] lastGamepadButtonRepeats = new DateTime[GamePad.MaximumGamePadCount];
|
/// This field represents the deadzone that gamepad <see cref="Buttons"/> have when input is queried for them using this input handler.
|
||||||
private readonly bool[] triggerGamepadButtonRepeat = new bool[GamePad.MaximumGamePadCount];
|
/// A deadzone is the percentage (between 0 and 1) that an analog value has to exceed for it to be considered down (<see cref="IsGamepadButtonDown"/>) or pressed (<see cref="IsGamepadButtonPressed"/>).
|
||||||
private readonly Buttons?[] heldGamepadButtons = new Buttons?[GamePad.MaximumGamePadCount];
|
/// Querying of analog values is done using <see cref="GamepadExtensions.GetAnalogValue"/>.
|
||||||
|
/// </summary>
|
||||||
|
public float GamepadButtonDeadzone;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An array of all <see cref="Keys"/>, <see cref="Buttons"/> and <see cref="MouseButton"/> values that are currently down.
|
/// An array of all <see cref="Keys"/>, <see cref="Buttons"/> and <see cref="MouseButton"/> values that are currently down.
|
||||||
/// Note that this value only gets set if <see cref="StoreAllActiveInputs"/> is true.
|
/// Additionally, <see cref="TryGetDownTime"/> or <see cref="GetDownTime"/> can be used to determine the amount of time that a given input has been down for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericInput[] InputsDown { get; private set; } = Array.Empty<GenericInput>();
|
public GenericInput[] InputsDown { get; private set; } = Array.Empty<GenericInput>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An array of all <see cref="Keys"/>, <see cref="Buttons"/> and <see cref="MouseButton"/> that are currently considered pressed.
|
/// An array of all <see cref="Keys"/>, <see cref="Buttons"/> and <see cref="MouseButton"/> that are currently considered pressed.
|
||||||
/// An input is considered pressed if it was up in the last update, and is up in the current one.
|
/// An input is considered pressed if it was up in the last update, and is up in the current one.
|
||||||
/// Note that this value only gets set if <see cref="StoreAllActiveInputs"/> is true.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericInput[] InputsPressed { get; private set; } = Array.Empty<GenericInput>();
|
public GenericInput[] InputsPressed { get; private set; } = Array.Empty<GenericInput>();
|
||||||
private readonly List<GenericInput> inputsDownAccum = new List<GenericInput>();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this field to false to enable <see cref="InputsDown"/> and <see cref="InputsPressed"/> being calculated.
|
/// Contains the touch state from the last update call
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool StoreAllActiveInputs;
|
public TouchCollection LastTouchState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the current touch state
|
||||||
|
/// </summary>
|
||||||
|
public TouchCollection TouchState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the <see cref="LastTouchState"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
|
||||||
|
/// </summary>
|
||||||
|
public IList<TouchLocation> LastViewportTouchState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the <see cref="TouchState"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
|
||||||
|
/// </summary>
|
||||||
|
public IList<TouchLocation> ViewportTouchState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the amount of gamepads that are currently connected.
|
||||||
|
/// This field is automatically updated in <see cref="Update()"/>
|
||||||
|
/// </summary>
|
||||||
|
public int ConnectedGamepads { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the mouse state from the last update call
|
||||||
|
/// </summary>
|
||||||
|
public MouseState LastMouseState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the current mouse state
|
||||||
|
/// </summary>
|
||||||
|
public MouseState MouseState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the position of the mouse from the last update call, extracted from <see cref="LastMouseState"/>
|
||||||
|
/// </summary>
|
||||||
|
public Point LastMousePosition => this.LastMouseState.Position;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the <see cref="LastMousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
|
||||||
|
/// </summary>
|
||||||
|
public Point LastViewportMousePosition => this.LastMousePosition + this.ViewportOffset;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the current position of the mouse, extracted from <see cref="MouseState"/>
|
||||||
|
/// </summary>
|
||||||
|
public Point MousePosition => this.MouseState.Position;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the <see cref="MousePosition"/>, but with the <see cref="GraphicsDevice.Viewport"/> taken into account.
|
||||||
|
/// </summary>
|
||||||
|
public Point ViewportMousePosition => this.MousePosition + this.ViewportOffset;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the current scroll wheel value, in increments of 120
|
||||||
|
/// </summary>
|
||||||
|
public int ScrollWheel => this.MouseState.ScrollWheelValue;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the scroll wheel value from the last update call, in increments of 120
|
||||||
|
/// </summary>
|
||||||
|
public int LastScrollWheel => this.LastMouseState.ScrollWheelValue;
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the keyboard state from the last update call
|
||||||
|
/// </summary>
|
||||||
|
public KeyboardState LastKeyboardState { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the current keyboard state
|
||||||
|
/// </summary>
|
||||||
|
public KeyboardState KeyboardState { get; private set; }
|
||||||
|
|
||||||
|
private readonly GamePadState[] lastGamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
||||||
|
private readonly GamePadState[] gamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
||||||
|
private readonly DateTime[] lastGamepadButtonRepeats = new DateTime[GamePad.MaximumGamePadCount];
|
||||||
|
private readonly bool[] triggerGamepadButtonRepeat = new bool[GamePad.MaximumGamePadCount];
|
||||||
|
private readonly Buttons?[] heldGamepadButtons = new Buttons?[GamePad.MaximumGamePadCount];
|
||||||
|
private readonly List<GestureSample> gestures = new List<GestureSample>();
|
||||||
|
|
||||||
|
private Point ViewportOffset => new Point(-this.Game.GraphicsDevice.Viewport.X, -this.Game.GraphicsDevice.Viewport.Y);
|
||||||
|
private Dictionary<(GenericInput, int), DateTime> inputsDownAccum = new Dictionary<(GenericInput, int), DateTime>();
|
||||||
|
private Dictionary<(GenericInput, int), DateTime> inputsDown = new Dictionary<(GenericInput, int), DateTime>();
|
||||||
|
private DateTime lastKeyRepeat;
|
||||||
|
private bool triggerKeyRepeat;
|
||||||
|
private Keys heldKey;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new input handler with optional initial values.
|
/// Creates a new input handler with optional initial values.
|
||||||
|
@ -141,13 +156,11 @@ namespace MLEM.Input {
|
||||||
/// <param name="handleMouse">If mouse input should be handled</param>
|
/// <param name="handleMouse">If mouse input should be handled</param>
|
||||||
/// <param name="handleGamepads">If gamepad input should be handled</param>
|
/// <param name="handleGamepads">If gamepad input should be handled</param>
|
||||||
/// <param name="handleTouch">If touch input should be handled</param>
|
/// <param name="handleTouch">If touch input should be handled</param>
|
||||||
/// <param name="storeAllActiveInputs">Whether all inputs that are currently down and pressed should be calculated each update</param>
|
public InputHandler(Game game, bool handleKeyboard = true, bool handleMouse = true, bool handleGamepads = true, bool handleTouch = true) : base(game) {
|
||||||
public InputHandler(Game game, bool handleKeyboard = true, bool handleMouse = true, bool handleGamepads = true, bool handleTouch = true, bool storeAllActiveInputs = true) : base(game) {
|
|
||||||
this.HandleKeyboard = handleKeyboard;
|
this.HandleKeyboard = handleKeyboard;
|
||||||
this.HandleMouse = handleMouse;
|
this.HandleMouse = handleMouse;
|
||||||
this.HandleGamepads = handleGamepads;
|
this.HandleGamepads = handleGamepads;
|
||||||
this.HandleTouch = handleTouch;
|
this.HandleTouch = handleTouch;
|
||||||
this.StoreAllActiveInputs = storeAllActiveInputs;
|
|
||||||
this.Gestures = this.gestures.AsReadOnly();
|
this.Gestures = this.gestures.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,42 +169,28 @@ namespace MLEM.Input {
|
||||||
/// Call this in your <see cref="Game.Update"/> method.
|
/// Call this in your <see cref="Game.Update"/> method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Update() {
|
public void Update() {
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
var active = this.Game.IsActive;
|
var active = this.Game.IsActive;
|
||||||
if (this.HandleKeyboard) {
|
if (this.HandleKeyboard) {
|
||||||
this.LastKeyboardState = this.KeyboardState;
|
this.LastKeyboardState = this.KeyboardState;
|
||||||
this.KeyboardState = active ? Keyboard.GetState() : default;
|
this.KeyboardState = active ? Keyboard.GetState() : default;
|
||||||
var pressedKeys = this.KeyboardState.GetPressedKeys();
|
var pressedKeys = this.KeyboardState.GetPressedKeys();
|
||||||
if (this.StoreAllActiveInputs) {
|
foreach (var pressed in pressedKeys)
|
||||||
foreach (var pressed in pressedKeys)
|
this.AccumulateDown(pressed, -1);
|
||||||
this.inputsDownAccum.Add(pressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.HandleKeyboardRepeats) {
|
if (this.HandleKeyboardRepeats) {
|
||||||
this.triggerKeyRepeat = false;
|
this.triggerKeyRepeat = false;
|
||||||
if (this.heldKey == Keys.None) {
|
// the key that started being held most recently should be the one being repeated
|
||||||
// if we're not repeating a key, set the first key being held to the repeat key
|
this.heldKey = pressedKeys.OrderBy(k => this.GetDownTime(k)).FirstOrDefault();
|
||||||
// note that modifier keys don't count as that wouldn't really make sense
|
if (this.TryGetDownTime(this.heldKey, out var heldTime)) {
|
||||||
var key = pressedKeys.FirstOrDefault(k => !k.IsModifier());
|
// if we've been holding the key longer than the initial delay...
|
||||||
if (key != Keys.None) {
|
if (heldTime >= this.KeyRepeatDelay) {
|
||||||
this.heldKey = key;
|
var diff = now - this.lastKeyRepeat;
|
||||||
this.heldKeyStart = DateTime.UtcNow;
|
// and we've been holding it for longer than a repeat...
|
||||||
}
|
if (diff >= this.KeyRepeatRate) {
|
||||||
} else {
|
this.lastKeyRepeat = now;
|
||||||
// if the repeating key isn't being held anymore, reset
|
// then trigger a repeat, causing IsKeyPressed to be true once
|
||||||
if (!this.IsKeyDown(this.heldKey)) {
|
this.triggerKeyRepeat = true;
|
||||||
this.heldKey = Keys.None;
|
|
||||||
} else {
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
var holdTime = now - this.heldKeyStart;
|
|
||||||
// if we've been holding the key longer than the initial delay...
|
|
||||||
if (holdTime >= this.KeyRepeatDelay) {
|
|
||||||
var diff = now - this.lastKeyRepeat;
|
|
||||||
// and we've been holding it for longer than a repeat...
|
|
||||||
if (diff >= this.KeyRepeatRate) {
|
|
||||||
this.lastKeyRepeat = now;
|
|
||||||
// then trigger a repeat, causing IsKeyPressed to be true once
|
|
||||||
this.triggerKeyRepeat = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,11 +202,9 @@ namespace MLEM.Input {
|
||||||
var state = Mouse.GetState();
|
var state = Mouse.GetState();
|
||||||
if (active && this.Game.GraphicsDevice.Viewport.Bounds.Contains(state.Position)) {
|
if (active && this.Game.GraphicsDevice.Viewport.Bounds.Contains(state.Position)) {
|
||||||
this.MouseState = state;
|
this.MouseState = state;
|
||||||
if (this.StoreAllActiveInputs) {
|
foreach (var button in MouseExtensions.MouseButtons) {
|
||||||
foreach (var button in MouseExtensions.MouseButtons) {
|
if (state.GetState(button) == ButtonState.Pressed)
|
||||||
if (state.GetState(button) == ButtonState.Pressed)
|
this.AccumulateDown(button, -1);
|
||||||
this.inputsDownAccum.Add(button);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// mouse position and scroll wheel value should be preserved when the mouse is out of bounds
|
// mouse position and scroll wheel value should be preserved when the mouse is out of bounds
|
||||||
|
@ -219,48 +216,33 @@ namespace MLEM.Input {
|
||||||
this.ConnectedGamepads = GamePad.MaximumGamePadCount;
|
this.ConnectedGamepads = GamePad.MaximumGamePadCount;
|
||||||
for (var i = 0; i < GamePad.MaximumGamePadCount; i++) {
|
for (var i = 0; i < GamePad.MaximumGamePadCount; i++) {
|
||||||
this.lastGamepads[i] = this.gamepads[i];
|
this.lastGamepads[i] = this.gamepads[i];
|
||||||
var state = GamePadState.Default;
|
this.gamepads[i] = GamePadState.Default;
|
||||||
if (GamePad.GetCapabilities(i).IsConnected) {
|
if (GamePad.GetCapabilities(i).IsConnected) {
|
||||||
if (active) {
|
if (active) {
|
||||||
state = GamePad.GetState(i);
|
this.gamepads[i] = GamePad.GetState(i);
|
||||||
if (this.StoreAllActiveInputs) {
|
foreach (var button in EnumHelper.Buttons) {
|
||||||
foreach (var button in EnumHelper.Buttons) {
|
if (this.IsGamepadButtonDown(button, i))
|
||||||
if (state.IsButtonDown(button))
|
this.AccumulateDown(button, i);
|
||||||
this.inputsDownAccum.Add(button);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (this.ConnectedGamepads > i) {
|
||||||
if (this.ConnectedGamepads > i)
|
this.ConnectedGamepads = i;
|
||||||
this.ConnectedGamepads = i;
|
|
||||||
}
|
}
|
||||||
this.gamepads[i] = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.HandleGamepadRepeats) {
|
if (this.HandleGamepadRepeats) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
this.triggerGamepadButtonRepeat[i] = false;
|
this.triggerGamepadButtonRepeat[i] = false;
|
||||||
|
this.heldGamepadButtons[i] = EnumHelper.Buttons
|
||||||
if (!this.heldGamepadButtons[i].HasValue) {
|
.Where(b => this.IsGamepadButtonDown(b, i))
|
||||||
foreach (var b in EnumHelper.Buttons) {
|
.OrderBy(b => this.GetDownTime(b, i))
|
||||||
if (this.IsGamepadButtonDown(b, i)) {
|
.Cast<Buttons?>().FirstOrDefault();
|
||||||
this.heldGamepadButtons[i] = b;
|
if (this.heldGamepadButtons[i].HasValue && this.TryGetDownTime(this.heldGamepadButtons[i].Value, out var heldTime, i)) {
|
||||||
this.heldGamepadButtonStarts[i] = DateTime.UtcNow;
|
if (heldTime >= this.KeyRepeatDelay) {
|
||||||
break;
|
var diff = now - this.lastGamepadButtonRepeats[i];
|
||||||
}
|
if (diff >= this.KeyRepeatRate) {
|
||||||
}
|
this.lastGamepadButtonRepeats[i] = now;
|
||||||
} else {
|
this.triggerGamepadButtonRepeat[i] = true;
|
||||||
if (!this.IsGamepadButtonDown(this.heldGamepadButtons[i].Value, i)) {
|
|
||||||
this.heldGamepadButtons[i] = null;
|
|
||||||
} else {
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
var holdTime = now - this.heldGamepadButtonStarts[i];
|
|
||||||
if (holdTime >= this.KeyRepeatDelay) {
|
|
||||||
var diff = now - this.lastGamepadButtonRepeats[i];
|
|
||||||
if (diff >= this.KeyRepeatRate) {
|
|
||||||
this.lastGamepadButtonRepeats[i] = now;
|
|
||||||
this.triggerGamepadButtonRepeat[i] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,22 +252,34 @@ namespace MLEM.Input {
|
||||||
|
|
||||||
if (this.HandleTouch) {
|
if (this.HandleTouch) {
|
||||||
this.LastTouchState = this.TouchState;
|
this.LastTouchState = this.TouchState;
|
||||||
|
this.LastViewportTouchState = this.ViewportTouchState;
|
||||||
|
|
||||||
this.TouchState = active ? TouchPanel.GetState() : default;
|
this.TouchState = active ? TouchPanel.GetState() : default;
|
||||||
|
if (this.TouchState.Count > 0 && this.ViewportOffset != Point.Zero) {
|
||||||
|
this.ViewportTouchState = new List<TouchLocation>();
|
||||||
|
foreach (var touch in this.TouchState) {
|
||||||
|
touch.TryGetPreviousLocation(out var previous);
|
||||||
|
this.ViewportTouchState.Add(new TouchLocation(touch.Id, touch.State, touch.Position + this.ViewportOffset.ToVector2(), previous.State, previous.Position + this.ViewportOffset.ToVector2()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.ViewportTouchState = this.TouchState;
|
||||||
|
}
|
||||||
|
|
||||||
this.gestures.Clear();
|
this.gestures.Clear();
|
||||||
while (active && TouchPanel.IsGestureAvailable)
|
while (active && TouchPanel.IsGestureAvailable)
|
||||||
this.gestures.Add(TouchPanel.ReadGesture());
|
this.gestures.Add(TouchPanel.ReadGesture());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.StoreAllActiveInputs) {
|
if (this.inputsDownAccum.Count <= 0) {
|
||||||
if (this.inputsDownAccum.Count <= 0) {
|
this.InputsPressed = Array.Empty<GenericInput>();
|
||||||
this.InputsPressed = Array.Empty<GenericInput>();
|
this.InputsDown = Array.Empty<GenericInput>();
|
||||||
this.InputsDown = Array.Empty<GenericInput>();
|
this.inputsDown.Clear();
|
||||||
} else {
|
} else {
|
||||||
this.InputsPressed = this.inputsDownAccum.Where(i => !this.InputsDown.Contains(i)).ToArray();
|
this.InputsPressed = this.inputsDownAccum.Keys.Where(kv => this.IsPressed(kv.Item1, kv.Item2)).Select(kv => kv.Item1).ToArray();
|
||||||
this.InputsDown = this.inputsDownAccum.ToArray();
|
this.InputsDown = this.inputsDownAccum.Keys.Select(kv => kv.Item1).ToArray();
|
||||||
this.inputsDownAccum.Clear();
|
// swapping these collections means that we don't have to keep moving entries between them
|
||||||
}
|
(this.inputsDown, this.inputsDownAccum) = (this.inputsDownAccum, this.inputsDown);
|
||||||
|
this.inputsDownAccum.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,45 +413,49 @@ namespace MLEM.Input {
|
||||||
/// <inheritdoc cref="GamePadState.IsButtonDown"/>
|
/// <inheritdoc cref="GamePadState.IsButtonDown"/>
|
||||||
public bool IsGamepadButtonDown(Buttons button, int index = -1) {
|
public bool IsGamepadButtonDown(Buttons button, int index = -1) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++)
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
if (this.GetGamepadState(i).IsButtonDown(button))
|
if (this.GetGamepadState(i).GetAnalogValue(button) > this.GamepadButtonDeadzone)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.GetGamepadState(index).IsButtonDown(button);
|
return this.GetGamepadState(index).GetAnalogValue(button) > this.GamepadButtonDeadzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GamePadState.IsButtonUp"/>
|
/// <inheritdoc cref="GamePadState.IsButtonUp"/>
|
||||||
public bool IsGamepadButtonUp(Buttons button, int index = -1) {
|
public bool IsGamepadButtonUp(Buttons button, int index = -1) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++)
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
if (this.GetGamepadState(i).IsButtonUp(button))
|
if (this.GetGamepadState(i).GetAnalogValue(button) <= this.GamepadButtonDeadzone)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.GetGamepadState(index).IsButtonUp(button);
|
return this.GetGamepadState(index).GetAnalogValue(button) <= this.GamepadButtonDeadzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GamePadState.IsButtonDown"/>
|
/// <inheritdoc cref="GamePadState.IsButtonDown"/>
|
||||||
public bool WasGamepadButtonDown(Buttons button, int index = -1) {
|
public bool WasGamepadButtonDown(Buttons button, int index = -1) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++)
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
if (this.GetLastGamepadState(i).IsButtonDown(button))
|
if (this.GetLastGamepadState(i).GetAnalogValue(button) > this.GamepadButtonDeadzone)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.GetLastGamepadState(index).IsButtonDown(button);
|
return this.GetLastGamepadState(index).GetAnalogValue(button) > this.GamepadButtonDeadzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="GamePadState.IsButtonUp"/>
|
/// <inheritdoc cref="GamePadState.IsButtonUp"/>
|
||||||
public bool WasGamepadButtonUp(Buttons button, int index = -1) {
|
public bool WasGamepadButtonUp(Buttons button, int index = -1) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++)
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
if (this.GetLastGamepadState(i).IsButtonUp(button))
|
if (this.GetLastGamepadState(i).GetAnalogValue(button) <= this.GamepadButtonDeadzone)
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.GetLastGamepadState(index).IsButtonUp(button);
|
return this.GetLastGamepadState(index).GetAnalogValue(button) <= this.GamepadButtonDeadzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -471,9 +469,10 @@ namespace MLEM.Input {
|
||||||
public bool IsGamepadButtonPressed(Buttons button, int index = -1) {
|
public bool IsGamepadButtonPressed(Buttons button, int index = -1) {
|
||||||
if (this.HandleGamepadRepeats) {
|
if (this.HandleGamepadRepeats) {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
for (var i = 0; i < this.ConnectedGamepads; i++)
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
||||||
if (this.heldGamepadButtons[i] == button && this.triggerGamepadButtonRepeat[i])
|
if (this.heldGamepadButtons[i] == button && this.triggerGamepadButtonRepeat[i])
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
} else if (this.heldGamepadButtons[index] == button && this.triggerGamepadButtonRepeat[index]) {
|
} else if (this.heldGamepadButtons[index] == button && this.triggerGamepadButtonRepeat[index]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -510,6 +509,22 @@ namespace MLEM.Input {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries for a gesture of the given type that finished during the current update call.
|
||||||
|
/// Unlike <see cref="GetGesture"/>, the return value of this method takes the <see cref="GraphicsDevice.Viewport"/> into account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of gesture to query for</param>
|
||||||
|
/// <param name="sample">The resulting gesture sample with the <see cref="GraphicsDevice.Viewport"/> taken into account, or default if there isn't one</param>
|
||||||
|
/// <returns>True if a gesture of the type was found, otherwise false</returns>
|
||||||
|
public bool GetViewportGesture(GestureType type, out GestureSample sample) {
|
||||||
|
if (this.GetGesture(type, out var original)) {
|
||||||
|
sample = new GestureSample(original.GestureType, original.Timestamp, original.Position + this.ViewportOffset.ToVector2(), original.Position2 + this.ViewportOffset.ToVector2(), original.Delta, original.Delta2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sample = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns if a given control of any kind is down.
|
/// Returns if a given control of any kind is down.
|
||||||
/// This is a helper function that can be passed a <see cref="Keys"/>, <see cref="Buttons"/> or <see cref="MouseButton"/>.
|
/// This is a helper function that can be passed a <see cref="Keys"/>, <see cref="Buttons"/> or <see cref="MouseButton"/>.
|
||||||
|
@ -600,6 +615,38 @@ namespace MLEM.Input {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve the amount of time that a given <see cref="GenericInput"/> has been held down for.
|
||||||
|
/// If the input is currently down, this method returns true and the amount of time that it has been down for is stored in <paramref name="downTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input whose down time to query.</param>
|
||||||
|
/// <param name="downTime">The resulting down time, or <see cref="TimeSpan.Zero"/> if the input is not being held.</param>
|
||||||
|
/// <param name="index">The index of the gamepad to query (if applicable), or -1 for any gamepad.</param>
|
||||||
|
/// <returns>Whether the input is currently being held.</returns>
|
||||||
|
public bool TryGetDownTime(GenericInput input, out TimeSpan downTime, int index = -1) {
|
||||||
|
if (this.inputsDown.TryGetValue((input, index), out var start)) {
|
||||||
|
downTime = DateTime.UtcNow - start;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the amount of time that a given <see cref="GenericInput"/> has been held down for.
|
||||||
|
/// If this input isn't currently own, this method returns <see cref="TimeSpan.Zero"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input whose down time to query.</param>
|
||||||
|
/// <param name="index">The index of the gamepad to query (if applicable), or -1 for any gamepad.</param>
|
||||||
|
/// <returns>The resulting down time, or <see cref="TimeSpan.Zero"/> if the input is not being held.</returns>
|
||||||
|
public TimeSpan GetDownTime(GenericInput input, int index = -1) {
|
||||||
|
this.TryGetDownTime(input, out var time, index);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AccumulateDown(GenericInput input, int index) {
|
||||||
|
this.inputsDownAccum.Add((input, index), this.inputsDown.TryGetValue((input, index), out var start) ? start : DateTime.UtcNow);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper function to enable gestures for a <see cref="TouchPanel"/> easily.
|
/// Helper function to enable gestures for a <see cref="TouchPanel"/> easily.
|
||||||
/// Note that, if other gestures were previously enabled, they will not get overridden.
|
/// Note that, if other gestures were previously enabled, they will not get overridden.
|
||||||
|
|
|
@ -32,8 +32,7 @@ namespace MLEM.Input {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new keybind with no default combinations
|
/// Creates a new keybind with no default combinations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Keybind() {
|
public Keybind() {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new key combination to this keybind that can optionally be pressed for the keybind to trigger.
|
/// Adds a new key combination to this keybind that can optionally be pressed for the keybind to trigger.
|
||||||
|
@ -48,7 +47,28 @@ namespace MLEM.Input {
|
||||||
|
|
||||||
/// <inheritdoc cref="Add(MLEM.Input.GenericInput,MLEM.Input.GenericInput[])"/>
|
/// <inheritdoc cref="Add(MLEM.Input.GenericInput,MLEM.Input.GenericInput[])"/>
|
||||||
public Keybind Add(GenericInput key, ModifierKey modifier) {
|
public Keybind Add(GenericInput key, ModifierKey modifier) {
|
||||||
return this.Add(key, modifier.GetKeys().Select(m => (GenericInput) m).ToArray());
|
foreach (var mod in modifier.GetKeys())
|
||||||
|
this.Add(key, mod);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts a new key combination into the given <paramref name="index"/> of this keybind's combinations that can optionally be pressed for the keybind to trigger.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index to insert this combination into.</param>
|
||||||
|
/// <param name="key">The key to be pressed.</param>
|
||||||
|
/// <param name="modifiers">The modifier keys that have to be held down.</param>
|
||||||
|
/// <returns>This keybind, for chaining.</returns>
|
||||||
|
public Keybind Insert(int index, GenericInput key, params GenericInput[] modifiers) {
|
||||||
|
this.combinations = this.combinations.Take(index).Append(new Combination(key, modifiers)).Concat(this.combinations.Skip(index)).ToArray();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Insert(int,MLEM.Input.GenericInput,MLEM.Input.GenericInput[])"/>
|
||||||
|
public Keybind Insert(int index, GenericInput key, ModifierKey modifier) {
|
||||||
|
foreach (var mod in modifier.GetKeys().Reverse())
|
||||||
|
this.Insert(index, key, mod);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -135,6 +155,22 @@ namespace MLEM.Input {
|
||||||
yield return combination;
|
yield return combination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to retrieve the combination at the given <paramref name="index"/> within this keybind.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the combination to retrieve.</param>
|
||||||
|
/// <param name="combination">The combination, or default if this method returns false.</param>
|
||||||
|
/// <returns>Whether the combination could be successfully retrieved or the index was out of bounds of this keybind's combination collection.</returns>
|
||||||
|
public bool TryGetCombination(int index, out Combination combination) {
|
||||||
|
if (index >= 0 && index < this.combinations.Length) {
|
||||||
|
combination = this.combinations[index];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
combination = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts this keybind into an easily human-readable string.
|
/// Converts this keybind into an easily human-readable string.
|
||||||
/// When using <see cref="ToString()"/>, this method is used with <paramref name="joiner"/> set to ", ".
|
/// When using <see cref="ToString()"/>, this method is used with <paramref name="joiner"/> set to ", ".
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Ellpeck</Authors>
|
<Authors>Ellpeck</Authors>
|
||||||
<Description>MLEM Library for Extending MonoGame provides extension methods and additional features for MonoGame</Description>
|
<Description>MLEM Library for Extending MonoGame provides extension methods and additional features for MonoGame</Description>
|
||||||
|
@ -16,13 +16,13 @@
|
||||||
<PackageIcon>Logo.png</PackageIcon>
|
<PackageIcon>Logo.png</PackageIcon>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
<None Include="../Media/Logo.png" Pack="true" PackagePath="" />
|
||||||
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
<None Include="../Docs/index.md" Pack="true" PackagePath="README.md" />
|
||||||
|
|
|
@ -140,8 +140,7 @@ namespace MLEM.Misc {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void AddTextInputListener(GameWindow window, TextInputCallback callback) {
|
public override void AddTextInputListener(GameWindow window, TextInputCallback callback) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OpenLinkOrFile(string link) {
|
public override void OpenLinkOrFile(string link) {
|
||||||
|
@ -172,12 +171,10 @@ namespace MLEM.Misc {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void AddTextInputListener(GameWindow window, TextInputCallback callback) {
|
public override void AddTextInputListener(GameWindow window, TextInputCallback callback) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OpenLinkOrFile(string link) {
|
public override void OpenLinkOrFile(string link) {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,27 +62,21 @@ namespace MLEM.Misc {
|
||||||
/// Creates a new padding with the specified value, which will be applied to each edge.
|
/// Creates a new padding with the specified value, which will be applied to each edge.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The padding to apply to each edge</param>
|
/// <param name="value">The padding to apply to each edge</param>
|
||||||
public Padding(float value) :
|
public Padding(float value) : this(value, value) {}
|
||||||
this(value, value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new padding with the specified x and y values, applying them to both edges.
|
/// Creates a new padding with the specified x and y values, applying them to both edges.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x">The x padding, which will turn into the left and right padding</param>
|
/// <param name="x">The x padding, which will turn into the left and right padding</param>
|
||||||
/// <param name="y">The y padding, which till turn into the top and bottom padding</param>
|
/// <param name="y">The y padding, which till turn into the top and bottom padding</param>
|
||||||
public Padding(float x, float y) :
|
public Padding(float x, float y) : this(x, x, y, y) {}
|
||||||
this(x, x, y, y) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new padding from an existing padding, modifying it by growing or shrinking it.
|
/// Creates a new padding from an existing padding, modifying it by growing or shrinking it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="padding">The padding whose initial values to use</param>
|
/// <param name="padding">The padding whose initial values to use</param>
|
||||||
/// <param name="growth">The amount to grow each border by. Negative values will shrink the padding.</param>
|
/// <param name="growth">The amount to grow each border by. Negative values will shrink the padding.</param>
|
||||||
public Padding(Padding padding, float growth) :
|
public Padding(Padding padding, float growth) : this(padding.Left + growth, padding.Right + growth, padding.Top + growth, padding.Bottom + growth) {}
|
||||||
this(padding.Left + growth, padding.Right + growth, padding.Top + growth, padding.Bottom + growth) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implicitly creates a padding from the given two-dimensional vector.
|
/// Implicitly creates a padding from the given two-dimensional vector.
|
||||||
|
|
|
@ -105,49 +105,6 @@ namespace MLEM.Misc {
|
||||||
this.Height = size.Y;
|
this.Height = size.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new rectangle based on two corners that form a bounding box.
|
|
||||||
/// The resulting rectangle will encompass both corners as well as all of the space between them.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="corner1">The first corner to use</param>
|
|
||||||
/// <param name="corner2">The second corner to use</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static RectangleF FromCorners(Vector2 corner1, Vector2 corner2) {
|
|
||||||
var minX = Math.Min(corner1.X, corner2.X);
|
|
||||||
var minY = Math.Min(corner1.Y, corner2.Y);
|
|
||||||
var maxX = Math.Max(corner1.X, corner2.X);
|
|
||||||
var maxY = Math.Max(corner1.Y, corner2.Y);
|
|
||||||
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a float-based rectangle to an int-based rectangle, flooring each value in the process.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to convert</param>
|
|
||||||
/// <returns>The resulting rectangle</returns>
|
|
||||||
public static explicit operator Rectangle(RectangleF rect) {
|
|
||||||
return new Rectangle(rect.X.Floor(), rect.Y.Floor(), rect.Width.Floor(), rect.Height.Floor());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts an int-based rectangle to a float-based rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to convert</param>
|
|
||||||
/// <returns>The resulting rectangle</returns>
|
|
||||||
public static explicit operator RectangleF(Rectangle rect) {
|
|
||||||
return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Equals(RectangleF)"/>
|
|
||||||
public static bool operator ==(RectangleF a, RectangleF b) {
|
|
||||||
return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Equals(RectangleF)"/>
|
|
||||||
public static bool operator !=(RectangleF a, RectangleF b) {
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Contains(float, float)"/>
|
/// <inheritdoc cref="Rectangle.Contains(float, float)"/>
|
||||||
public bool Contains(float x, float y) {
|
public bool Contains(float x, float y) {
|
||||||
return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;
|
return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;
|
||||||
|
@ -196,6 +153,92 @@ namespace MLEM.Misc {
|
||||||
return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom;
|
return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Rectangle.Offset(float, float)"/>
|
||||||
|
public void Offset(float offsetX, float offsetY) {
|
||||||
|
this.X += offsetX;
|
||||||
|
this.Y += offsetY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Rectangle.Offset(Vector2)"/>
|
||||||
|
public void Offset(Vector2 amount) {
|
||||||
|
this.X += amount.X;
|
||||||
|
this.Y += amount.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the suqared distance between this rectangle and the <paramref name="value"/>.
|
||||||
|
/// The returned value is the smallest squared distance between any two edges or corners of the two rectangles.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The rectangle to calculate the squared distance to.</param>
|
||||||
|
/// <returns>The squared distance between the two rectangles.</returns>
|
||||||
|
public float DistanceSquared(RectangleF value) {
|
||||||
|
// we calculate the distance based on the quadrants that the other rectangle is in using 8 cases:
|
||||||
|
// 1 7 4
|
||||||
|
// 3 T 6
|
||||||
|
// 2 8 5
|
||||||
|
var valueIsAbove = value.Bottom < this.Top;
|
||||||
|
var valueIsBelow = value.Top > this.Bottom;
|
||||||
|
if (value.Right < this.Left) {
|
||||||
|
if (valueIsAbove) // 1
|
||||||
|
return Vector2.DistanceSquared(new Vector2(value.Right, value.Bottom), new Vector2(this.Left, this.Top));
|
||||||
|
if (valueIsBelow) // 2
|
||||||
|
return Vector2.DistanceSquared(new Vector2(value.Right, value.Top), new Vector2(this.Left, this.Bottom));
|
||||||
|
return (this.Left - value.Right) * (this.Left - value.Right); // 3
|
||||||
|
} else if (value.Left > this.Right) {
|
||||||
|
if (valueIsAbove) // 4
|
||||||
|
return Vector2.DistanceSquared(new Vector2(value.Left, value.Bottom), new Vector2(this.Right, this.Top));
|
||||||
|
if (valueIsBelow) // 5
|
||||||
|
return Vector2.DistanceSquared(new Vector2(value.Left, value.Top), new Vector2(this.Right, this.Bottom));
|
||||||
|
return (value.Left - this.Right) * (value.Left - this.Right); // 6
|
||||||
|
} else if (valueIsAbove) {
|
||||||
|
return (this.Top - value.Bottom) * (this.Top - value.Bottom); // 7
|
||||||
|
} else if (valueIsBelow) {
|
||||||
|
return (value.Top - this.Bottom) * (value.Top - this.Bottom); // 8
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the distance between this rectangle and the <paramref name="value"/>.
|
||||||
|
/// The returned value is the smallest distance between any two edges or corners of the two rectangles.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The rectangle to calculate the distance to.</param>
|
||||||
|
/// <returns>The distance between the two rectangles.</returns>
|
||||||
|
public float Distance(RectangleF value) {
|
||||||
|
return (float) Math.Sqrt(this.DistanceSquared(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns a string that represents the current object.</summary>
|
||||||
|
/// <returns>A string that represents the current object.</returns>
|
||||||
|
public override string ToString() {
|
||||||
|
return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Rectangle.Deconstruct"/>
|
||||||
|
public void Deconstruct(out float x, out float y, out float width, out float height) {
|
||||||
|
x = this.X;
|
||||||
|
y = this.Y;
|
||||||
|
width = this.Width;
|
||||||
|
height = this.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a float-based rectangle to an int-based rectangle, flooring each value in the process.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to convert</param>
|
||||||
|
/// <returns>The resulting rectangle</returns>
|
||||||
|
public static explicit operator Rectangle(RectangleF rect) {
|
||||||
|
return new Rectangle(rect.X.Floor(), rect.Y.Floor(), rect.Width.Floor(), rect.Height.Floor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Rectangle.Union(Rectangle, Rectangle)"/>
|
||||||
|
public static RectangleF Union(RectangleF value1, RectangleF value2) {
|
||||||
|
var x = Math.Min(value1.X, value2.X);
|
||||||
|
var y = Math.Min(value1.Y, value2.Y);
|
||||||
|
return new RectangleF(x, y, Math.Max(value1.Right, value2.Right) - x, Math.Max(value1.Bottom, value2.Bottom) - y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Intersect(Rectangle, Rectangle)"/>
|
/// <inheritdoc cref="Rectangle.Intersect(Rectangle, Rectangle)"/>
|
||||||
public static RectangleF Intersect(RectangleF value1, RectangleF value2) {
|
public static RectangleF Intersect(RectangleF value1, RectangleF value2) {
|
||||||
if (value1.Intersects(value2)) {
|
if (value1.Intersects(value2)) {
|
||||||
|
@ -209,37 +252,38 @@ namespace MLEM.Misc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Offset(float, float)"/>
|
/// <summary>
|
||||||
public void Offset(float offsetX, float offsetY) {
|
/// Creates a new rectangle based on two corners that form a bounding box.
|
||||||
this.X += offsetX;
|
/// The resulting rectangle will encompass both corners as well as all of the space between them.
|
||||||
this.Y += offsetY;
|
/// </summary>
|
||||||
|
/// <param name="corner1">The first corner to use</param>
|
||||||
|
/// <param name="corner2">The second corner to use</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static RectangleF FromCorners(Vector2 corner1, Vector2 corner2) {
|
||||||
|
var minX = Math.Min(corner1.X, corner2.X);
|
||||||
|
var minY = Math.Min(corner1.Y, corner2.Y);
|
||||||
|
var maxX = Math.Max(corner1.X, corner2.X);
|
||||||
|
var maxY = Math.Max(corner1.Y, corner2.Y);
|
||||||
|
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Offset(Vector2)"/>
|
/// <summary>
|
||||||
public void Offset(Vector2 amount) {
|
/// Converts an int-based rectangle to a float-based rectangle.
|
||||||
this.X += amount.X;
|
/// </summary>
|
||||||
this.Y += amount.Y;
|
/// <param name="rect">The rectangle to convert</param>
|
||||||
|
/// <returns>The resulting rectangle</returns>
|
||||||
|
public static explicit operator RectangleF(Rectangle rect) {
|
||||||
|
return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns a string that represents the current object.</summary>
|
/// <inheritdoc cref="Equals(RectangleF)"/>
|
||||||
/// <returns>A string that represents the current object.</returns>
|
public static bool operator ==(RectangleF a, RectangleF b) {
|
||||||
public override string ToString() {
|
return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
|
||||||
return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Union(Rectangle, Rectangle)"/>
|
/// <inheritdoc cref="Equals(RectangleF)"/>
|
||||||
public static RectangleF Union(RectangleF value1, RectangleF value2) {
|
public static bool operator !=(RectangleF a, RectangleF b) {
|
||||||
var x = Math.Min(value1.X, value2.X);
|
return !(a == b);
|
||||||
var y = Math.Min(value1.Y, value2.Y);
|
|
||||||
return new RectangleF(x, y, Math.Max(value1.Right, value2.Right) - x, Math.Max(value1.Bottom, value2.Bottom) - y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Rectangle.Deconstruct"/>
|
|
||||||
public void Deconstruct(out float x, out float y, out float width, out float height) {
|
|
||||||
x = this.X;
|
|
||||||
y = this.Y;
|
|
||||||
width = this.Width;
|
|
||||||
height = this.Height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@ namespace MLEM.Pathfinding {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AStar2(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
|
public AStar2(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
|
||||||
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {
|
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Point AddPositions(Point first, Point second) {
|
protected override Point AddPositions(Point first, Point second) {
|
||||||
|
|
|
@ -35,8 +35,7 @@ namespace MLEM.Pathfinding {
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AStar3(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
|
public AStar3(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
|
||||||
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {
|
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Vector3 AddPositions(Vector3 first, Vector3 second) {
|
protected override Vector3 AddPositions(Vector3 first, Vector3 second) {
|
||||||
|
|
|
@ -19,8 +19,7 @@ namespace MLEM.Sound {
|
||||||
/// Creates a new sound effect instance handler with the given settings
|
/// Creates a new sound effect instance handler with the given settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="game">The game instance</param>
|
/// <param name="game">The game instance</param>
|
||||||
public SoundEffectInstanceHandler(Game game) : base(game) {
|
public SoundEffectInstanceHandler(Game game) : base(game) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Update()"/>
|
/// <inheritdoc cref="Update()"/>
|
||||||
public override void Update(GameTime gameTime) {
|
public override void Update(GameTime gameTime) {
|
||||||
|
@ -36,8 +35,7 @@ namespace MLEM.Sound {
|
||||||
for (var i = this.playingSounds.Count - 1; i >= 0; i--) {
|
for (var i = this.playingSounds.Count - 1; i >= 0; i--) {
|
||||||
var entry = this.playingSounds[i];
|
var entry = this.playingSounds[i];
|
||||||
if (entry.Instance.IsDisposed || entry.Instance.State == SoundState.Stopped) {
|
if (entry.Instance.IsDisposed || entry.Instance.State == SoundState.Stopped) {
|
||||||
entry.Instance.Stop(true);
|
entry.StopAndNotify();
|
||||||
entry.OnStopped?.Invoke(entry.Instance);
|
|
||||||
this.playingSounds.RemoveAt(i);
|
this.playingSounds.RemoveAt(i);
|
||||||
} else {
|
} else {
|
||||||
entry.TryApply3D(this.listeners);
|
entry.TryApply3D(this.listeners);
|
||||||
|
@ -69,6 +67,16 @@ namespace MLEM.Sound {
|
||||||
entry.Instance.Resume();
|
entry.Instance.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops all of the sound effect instances in this handler
|
||||||
|
/// </summary>
|
||||||
|
public void Stop() {
|
||||||
|
this.playingSounds.RemoveAll(e => {
|
||||||
|
e.StopAndNotify();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new <see cref="SoundEffectInstance"/> to this handler.
|
/// Adds a new <see cref="SoundEffectInstance"/> to this handler.
|
||||||
/// This also starts playing the instance.
|
/// This also starts playing the instance.
|
||||||
|
@ -132,7 +140,7 @@ namespace MLEM.Sound {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly SoundEffectInstance Instance;
|
public readonly SoundEffectInstance Instance;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An action that is invoked when this entry's <see cref="Instance"/> is stopped.
|
/// An action that is invoked when this entry's <see cref="Instance"/> is stopped or after it finishes naturally.
|
||||||
/// This action is invoked in <see cref="SoundEffectInstanceHandler.Update()"/>.
|
/// This action is invoked in <see cref="SoundEffectInstanceHandler.Update()"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Action<SoundEffectInstance> OnStopped;
|
public readonly Action<SoundEffectInstance> OnStopped;
|
||||||
|
@ -153,6 +161,11 @@ namespace MLEM.Sound {
|
||||||
this.Instance.Apply3D(listeners, this.Emitter);
|
this.Instance.Apply3D(listeners, this.Emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void StopAndNotify() {
|
||||||
|
this.Instance.Stop(true);
|
||||||
|
this.OnStopped?.Invoke(this.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,14 +53,10 @@ namespace MLEM.Textures {
|
||||||
/// <param name="paddingTop">The padding on the top edge</param>
|
/// <param name="paddingTop">The padding on the top edge</param>
|
||||||
/// <param name="paddingBottom">The padding on the bottom edge</param>
|
/// <param name="paddingBottom">The padding on the bottom edge</param>
|
||||||
/// <param name="mode">The mode to use for drawing this nine patch, defaults to <see cref="NinePatchMode.Stretch"/></param>
|
/// <param name="mode">The mode to use for drawing this nine patch, defaults to <see cref="NinePatchMode.Stretch"/></param>
|
||||||
public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) :
|
public NinePatch(TextureRegion texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) : this(texture, new Padding(paddingLeft, paddingRight, paddingTop, paddingBottom), mode) {}
|
||||||
this(texture, new Padding(paddingLeft, paddingRight, paddingTop, paddingBottom), mode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="NinePatch(TextureRegion, int, int, int, int, NinePatchMode)"/>
|
/// <inheritdoc cref="NinePatch(TextureRegion, int, int, int, int, NinePatchMode)"/>
|
||||||
public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) :
|
public NinePatch(Texture2D texture, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, NinePatchMode mode = NinePatchMode.Stretch) : this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom, mode) {}
|
||||||
this(new TextureRegion(texture), paddingLeft, paddingRight, paddingTop, paddingBottom, mode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new nine patch from a texture and a uniform padding
|
/// Creates a new nine patch from a texture and a uniform padding
|
||||||
|
@ -68,14 +64,10 @@ namespace MLEM.Textures {
|
||||||
/// <param name="texture">The texture to use</param>
|
/// <param name="texture">The texture to use</param>
|
||||||
/// <param name="padding">The padding that each edge should have</param>
|
/// <param name="padding">The padding that each edge should have</param>
|
||||||
/// <param name="mode">The mode to use for drawing this nine patch, defaults to <see cref="NinePatchMode.Stretch"/></param>
|
/// <param name="mode">The mode to use for drawing this nine patch, defaults to <see cref="NinePatchMode.Stretch"/></param>
|
||||||
public NinePatch(Texture2D texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) :
|
public NinePatch(Texture2D texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) : this(new TextureRegion(texture), padding, mode) {}
|
||||||
this(new TextureRegion(texture), padding, mode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="NinePatch(TextureRegion, int, NinePatchMode)"/>
|
/// <inheritdoc cref="NinePatch(TextureRegion, int, NinePatchMode)"/>
|
||||||
public NinePatch(TextureRegion texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) :
|
public NinePatch(TextureRegion texture, int padding, NinePatchMode mode = NinePatchMode.Stretch) : this(texture, padding, padding, padding, padding, mode) {}
|
||||||
this(texture, padding, padding, padding, padding, mode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
internal RectangleF GetRectangleForIndex(RectangleF area, int index, float patchScale = 1) {
|
internal RectangleF GetRectangleForIndex(RectangleF area, int index, float patchScale = 1) {
|
||||||
var pl = this.Padding.Left * patchScale;
|
var pl = this.Padding.Left * patchScale;
|
||||||
|
|
|
@ -73,9 +73,7 @@ namespace MLEM.Textures {
|
||||||
/// Creates a new texture region that spans the entire texture
|
/// Creates a new texture region that spans the entire texture
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">The texture to use</param>
|
/// <param name="texture">The texture to use</param>
|
||||||
public TextureRegion(Texture2D texture) :
|
public TextureRegion(Texture2D texture) : this(texture, new Rectangle(0, 0, texture.Width, texture.Height)) {}
|
||||||
this(texture, new Rectangle(0, 0, texture.Width, texture.Height)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new texture region based on a texture and area coordinates
|
/// Creates a new texture region based on a texture and area coordinates
|
||||||
|
@ -85,9 +83,7 @@ namespace MLEM.Textures {
|
||||||
/// <param name="v">The y coordinate of the top left corner of this area</param>
|
/// <param name="v">The y coordinate of the top left corner of this area</param>
|
||||||
/// <param name="width">The width of this area</param>
|
/// <param name="width">The width of this area</param>
|
||||||
/// <param name="height">The height of this area</param>
|
/// <param name="height">The height of this area</param>
|
||||||
public TextureRegion(Texture2D texture, int u, int v, int width, int height) :
|
public TextureRegion(Texture2D texture, int u, int v, int width, int height) : this(texture, new Rectangle(u, v, width, height)) {}
|
||||||
this(texture, new Rectangle(u, v, width, height)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new texture region based on a texture, a position and a size
|
/// Creates a new texture region based on a texture, a position and a size
|
||||||
|
@ -95,18 +91,14 @@ namespace MLEM.Textures {
|
||||||
/// <param name="texture">The texture to use</param>
|
/// <param name="texture">The texture to use</param>
|
||||||
/// <param name="uv">The top left corner of this area</param>
|
/// <param name="uv">The top left corner of this area</param>
|
||||||
/// <param name="size">The size of this area</param>
|
/// <param name="size">The size of this area</param>
|
||||||
public TextureRegion(Texture2D texture, Point uv, Point size) :
|
public TextureRegion(Texture2D texture, Point uv, Point size) : this(texture, new Rectangle(uv, size)) {}
|
||||||
this(texture, new Rectangle(uv, size)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new texture region which is a sub-region of the given texture region
|
/// Creates a new texture region which is a sub-region of the given texture region
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="region">The texture region to create a sub-region of</param>
|
/// <param name="region">The texture region to create a sub-region of</param>
|
||||||
/// <param name="area">The new texture region area</param>
|
/// <param name="area">The new texture region area</param>
|
||||||
public TextureRegion(TextureRegion region, Rectangle area) :
|
public TextureRegion(TextureRegion region, Rectangle area) : this(region, area.Location, area.Size) {}
|
||||||
this(region, area.Location, area.Size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new texture region which is a sub-region of the given texture region
|
/// Creates a new texture region which is a sub-region of the given texture region
|
||||||
|
@ -116,9 +108,7 @@ namespace MLEM.Textures {
|
||||||
/// <param name="v">The y coordinate of the top left corner of this area</param>
|
/// <param name="v">The y coordinate of the top left corner of this area</param>
|
||||||
/// <param name="width">The width of this area</param>
|
/// <param name="width">The width of this area</param>
|
||||||
/// <param name="height">The height of this area</param>
|
/// <param name="height">The height of this area</param>
|
||||||
public TextureRegion(TextureRegion region, int u, int v, int width, int height) :
|
public TextureRegion(TextureRegion region, int u, int v, int width, int height) : this(region, new Point(u, v), new Point(width, height)) {}
|
||||||
this(region, new Point(u, v), new Point(width, height)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new texture region which is a sub-region of the given texture region
|
/// Creates a new texture region which is a sub-region of the given texture region
|
||||||
|
@ -126,8 +116,16 @@ namespace MLEM.Textures {
|
||||||
/// <param name="region">The texture region to create a sub-region of</param>
|
/// <param name="region">The texture region to create a sub-region of</param>
|
||||||
/// <param name="uv">The top left corner of this area</param>
|
/// <param name="uv">The top left corner of this area</param>
|
||||||
/// <param name="size">The size of this area</param>
|
/// <param name="size">The size of this area</param>
|
||||||
public TextureRegion(TextureRegion region, Point uv, Point size) :
|
public TextureRegion(TextureRegion region, Point uv, Point size) : this(region.Texture, region.Position + uv, size) {}
|
||||||
this(region.Texture, region.Position + uv, size) {
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="TextureRegion"/> that has the same <see cref="Texture"/>, <see cref="Pivot"/> and <see cref="Size"/> as this texture, but the returned region's <see cref="Position"/> will be offset by <paramref name="offset"/>.
|
||||||
|
/// Note that the <see cref="Name"/> is not preserved in the copy.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The offset to apply to the <see cref="Position"/></param>
|
||||||
|
/// <returns>An offset copy of this texture region</returns>
|
||||||
|
public TextureRegion OffsetCopy(Point offset) {
|
||||||
|
return new TextureRegion(this.Texture, this.Position + offset, this.Size) {Pivot = this.Pivot};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,9 +82,7 @@ namespace MLEM.Textures {
|
||||||
/// <param name="texture">The texture to use for this atlas</param>
|
/// <param name="texture">The texture to use for this atlas</param>
|
||||||
/// <param name="regionAmountX">The amount of texture regions in the x direction</param>
|
/// <param name="regionAmountX">The amount of texture regions in the x direction</param>
|
||||||
/// <param name="regionAmountY">The amount of texture regions in the y direction</param>
|
/// <param name="regionAmountY">The amount of texture regions in the y direction</param>
|
||||||
public UniformTextureAtlas(Texture2D texture, int regionAmountX, int regionAmountY) :
|
public UniformTextureAtlas(Texture2D texture, int regionAmountX, int regionAmountY) : this(new TextureRegion(texture), regionAmountX, regionAmountY) {}
|
||||||
this(new TextureRegion(texture), regionAmountX, regionAmountY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextureRegion GetOrAddRegion(Rectangle rect) {
|
private TextureRegion GetOrAddRegion(Rectangle rect) {
|
||||||
if (this.regions.TryGetValue(rect, out var region))
|
if (this.regions.TryGetValue(rect, out var region))
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
- **MLEM** is the base package, which provides extension methods and additional features for MonoGame
|
- **MLEM** is the base package, which provides extension methods and additional features for MonoGame
|
||||||
- **MLEM.Ui** features a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
|
- **MLEM.Ui** features a mouse, keyboard, gamepad and touch ready Ui system that features automatic anchoring, sizing and several ready-to-use element types
|
||||||
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame libraries
|
- **MLEM.Extended** ties in with MonoGame.Extended and other MonoGame libraries
|
||||||
- **MLEM.Data** provides simple data handling
|
- **MLEM.Data** provides simple loading and processing of textures and data
|
||||||
- **MLEM.Startup** combines MLEM with some other useful libraries into a quick Game startup class
|
- **MLEM.Startup** combines MLEM with some other useful libraries into a quick Game startup class
|
||||||
- **MLEM.Templates** contains cross-platform project templates
|
- **MLEM.Templates** contains cross-platform project templates
|
||||||
|
|
||||||
# Made with MLEM
|
# Made with MLEM
|
||||||
- [A Breath of Spring Air](https://ellpeck.itch.io/a-breath-of-spring-air), a short platformer ([Source](https://git.ellpeck.de/Ellpeck/GreatSpringGameJam))
|
- [A Breath of Spring Air](https://ellpeck.itch.io/a-breath-of-spring-air), a short platformer ([Source](https://git.ellpeck.de/Ellpeck/GreatSpringGameJam))
|
||||||
- [Don't Wake Up](https://ellpeck.itch.io/dont-wake-up), a short puzzle game ([Source](https://github.com/Ellpeck/DontLetGo))
|
- [Don't Wake Up](https://ellpeck.itch.io/dont-wake-up), a short puzzle game ([Source](https://github.com/Ellpeck/DontLetGo))
|
||||||
|
- [Pong clone](https://github.com/luanfagu/pong), a very simple pong clone ([Source](https://github.com/luanfagu/pong))
|
||||||
- [Tiny Life](https://tinylifegame.com), an isometric life simulation game ([Modding API](https://github.com/Ellpeck/TinyLifeExampleMod))
|
- [Tiny Life](https://tinylifegame.com), an isometric life simulation game ([Modding API](https://github.com/Ellpeck/TinyLifeExampleMod))
|
||||||
|
|
||||||
If you created a game with the help of MLEM, you can get it added to this list by submitting it on the [issue tracker](https://github.com/Ellpeck/MLEM/issues). If its source is public, other people will be able to use your project as an example, too!
|
If you created a game with the help of MLEM, you can get it added to this list by submitting it on the [issue tracker](https://github.com/Ellpeck/MLEM/issues). If its source is public, other people will be able to use your project as an example, too!
|
||||||
|
@ -37,8 +38,9 @@ MLEM's [text formatting system](https://mlem.ellpeck.de/articles/text_formatting
|
||||||
![An image showing text with various colors and other formatting](https://raw.githubusercontent.com/Ellpeck/MLEM/main/Media/Formatting.png)
|
![An image showing text with various colors and other formatting](https://raw.githubusercontent.com/Ellpeck/MLEM/main/Media/Formatting.png)
|
||||||
|
|
||||||
# Friends of MLEM
|
# Friends of MLEM
|
||||||
There are several other NuGet packages and tools that work well in combination with MonoGame and MLEM. Here are some of them:
|
There are several other libraries and tools that work well in combination with MonoGame and MLEM. Here are some of them:
|
||||||
- [Contentless](https://github.com/Ellpeck/Contentless), a tool that removes the need to add assets to the MonoGame Content Pipeline manually
|
- [Contentless](https://github.com/Ellpeck/Contentless), a tool that removes the need to add assets to the MonoGame Content Pipeline manually
|
||||||
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET Core applications into several distributable formats
|
- [GameBundle](https://github.com/Ellpeck/GameBundle), a tool that packages MonoGame and other .NET Core applications into several distributable formats
|
||||||
- [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended), a package that also provides several additional features for MonoGame
|
- [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended), a package that also provides several additional features for MonoGame
|
||||||
- [Coroutine](https://github.com/Ellpeck/Coroutine), a package that implements Unity-style coroutines for any project
|
- [Coroutine](https://github.com/Ellpeck/Coroutine), a package that implements Unity-style coroutines for any project
|
||||||
|
- [Illumilib](https://github.com/Ellpeck/Illumilib), a simple keyboard and mouse lighting library with support for Razer, Logitech and Corsair devices
|
||||||
|
|
|
@ -1,274 +1,274 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-down" compressionlevel="0" width="50" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="32">
|
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-down" compressionlevel="0" width="50" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="32">
|
||||||
<tileset firstgid="1" source="Tileset.tsx"/>
|
<tileset firstgid="1" source="Tileset.tsx" />
|
||||||
<layer id="1" name="Ground" width="50" height="50">
|
<layer id="1" name="Ground" width="50" height="50">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
450,450,450,450,450,451,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,450,451,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,450,451,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,450,451,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,420,483,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,164,40,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,420,483,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,164,40,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,420,483,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,420,483,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,420,483,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,420,483,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,100,72,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,451,3,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,451,3,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,452,419,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,452,419,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,451,3,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,452,419,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,452,419,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,39,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
450,450,450,450,451,3,3,36,38,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
450,450,450,450,451,3,3,36,66,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
450,450,450,450,451,3,3,36,66,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||||
450,450,450,420,483,3,3,68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
|
450,450,450,420,483,3,3,68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,34,69,69,69,69,69,69,69,69,69,69,69,69,69,
|
450,450,450,451,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,34,69,69,69,69,69,69,69,69,69,69,69,69,69,
|
||||||
450,450,450,452,419,3,3,3,3,3,100,72,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,417,418,419,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,3,3,417,418,
|
450,450,450,452,419,3,3,3,3,3,100,72,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,417,418,419,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,3,3,417,418,
|
||||||
450,450,450,450,451,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,417,453,450,451,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,3,417,453,2684355010,
|
450,450,450,450,451,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,417,453,450,451,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,3,417,453,2684355010,
|
||||||
450,450,450,450,451,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,
|
450,450,450,450,451,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,
|
||||||
450,450,450,450,451,3,3,3,3,3,164,40,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,449,2684355010,2684355010,2684355010,
|
450,450,450,450,451,3,3,3,3,3,164,40,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,3,449,2684355010,2684355010,2684355010,
|
||||||
450,450,450,420,483,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,
|
450,450,450,420,483,3,3,3,3,3,3,132,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,164,40,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,2684355010,
|
450,450,450,451,3,3,3,3,3,3,3,164,40,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,450,420,483,3,3,3,3,3,3,3,3,132,133,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
450,450,420,483,3,3,3,3,3,3,3,3,132,133,133,71,102,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,420,483,3,3,3,3,3,3,3,3,3,164,40,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,417,418,418,419,3,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
450,420,483,3,3,3,3,3,3,3,3,3,164,40,133,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,417,418,418,419,3,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,451,3,3,3,3,3,3,3,3,3,3,3,164,40,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,449,2684355010,2684355010,452,419,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
450,451,3,3,3,3,3,3,3,3,3,3,3,164,40,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,3,449,2684355010,2684355010,452,419,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,451,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,417,453,2684355010,2684355010,2684355010,451,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
450,451,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,417,453,2684355010,2684355010,2684355010,451,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,451,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
450,451,3,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,36,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,449,2684355010,2684355010,2684355010,2684355010,2684355010,
|
||||||
450,452,419,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,36,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,481,482,421,2684355010,2684355010,2684355010,
|
450,452,419,3,3,3,3,3,3,3,3,3,3,3,132,133,134,3,3,3,3,3,3,3,36,37,38,3,3,3,3,3,3,3,36,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,481,482,421,2684355010,2684355010,2684355010,
|
||||||
450,450,451,3,3,3,3,3,3,3,3,3,3,3,132,133,71,102,3,100,101,101,101,101,36,37,66,5,5,5,5,5,5,5,67,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,3,3,481,482,482,482,
|
450,450,451,3,3,3,3,3,3,3,3,3,3,3,132,133,71,102,3,100,101,101,101,101,36,37,66,5,5,5,5,5,5,5,67,37,38,449,2684355010,2684355010,2684355010,2684355010,451,3,3,3,481,482,482,482,
|
||||||
450,450,451,3,3,3,3,3,3,3,3,3,3,100,72,133,133,71,101,72,133,133,133,133,36,37,37,37,37,37,37,37,37,37,37,37,38,481,421,2684355010,2684355010,420,483,3,3,3,3,16,16,16,
|
450,450,451,3,3,3,3,3,3,3,3,3,3,100,72,133,133,71,101,72,133,133,133,133,36,37,37,37,37,37,37,37,37,37,37,37,38,481,421,2684355010,2684355010,420,483,3,3,3,3,16,16,16,
|
||||||
450,450,451,3,3,3,3,3,3,3,3,3,100,72,133,133,133,133,133,133,133,39,165,165,68,69,69,69,69,69,69,69,69,69,69,69,70,3,481,482,482,483,3,3,16,16,16,16,16,16,
|
450,450,451,3,3,3,3,3,3,3,3,3,100,72,133,133,133,133,133,133,133,39,165,165,68,69,69,69,69,69,69,69,69,69,69,69,70,3,481,482,482,483,3,3,16,16,16,16,16,16,
|
||||||
450,450,451,3,3,3,132,133,71,101,101,101,72,133,133,133,39,165,165,165,165,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,
|
450,450,451,3,3,3,132,133,71,101,101,101,72,133,133,133,39,165,165,165,165,166,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,
|
||||||
450,450,451,3,3,3,132,133,133,133,133,133,133,133,39,165,166,3,3,3,3,3,3,3,417,418,418,418,418,418,418,418,418,418,418,419,3,3,3,3,3,16,16,16,16,16,16,16,16,16,
|
450,450,451,3,3,3,132,133,133,133,133,133,133,133,39,165,166,3,3,3,3,3,3,3,417,418,418,418,418,418,418,418,418,418,418,419,3,3,3,3,3,16,16,16,16,16,16,16,16,16,
|
||||||
450,450,452,419,3,3,164,165,165,165,165,165,165,165,166,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,451,3,3,3,3,16,16,16,16,16,16,16,16,16,16,
|
450,450,452,419,3,3,164,165,165,165,165,165,165,165,166,3,3,3,3,3,3,3,3,417,453,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,451,3,3,3,3,16,16,16,16,16,16,16,16,16,16,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,481,421,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,420,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,481,421,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,2684355010,420,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,481,482,482,482,482,482,482,482,482,482,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,481,482,482,482,482,482,482,482,482,482,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,
|
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,
|
||||||
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,
|
450,450,450,451,3,3,3,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,
|
||||||
2684355010,450,420,483,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,
|
2684355010,450,420,483,3,3,3,3,3,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,
|
||||||
2684355010,420,483,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,
|
2684355010,420,483,3,3,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,
|
||||||
482,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,
|
482,483,3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,
|
||||||
3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,
|
3,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,
|
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
16,16,16,16,16,16,16,16,16,16,16,16,16,16,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="2" name="Ground1" width="50" height="50">
|
<layer id="2" name="Ground1" width="50" height="50">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,18,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,18,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,18,19,19,54,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,18,19,19,54,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,18,19,19,54,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,18,19,19,54,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,18,54,0,0,0,21,83,83,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,18,54,0,0,0,21,83,83,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,18,19,54,0,0,21,83,84,17,17,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,18,19,54,0,0,21,83,84,17,17,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,18,54,0,0,21,83,84,17,17,17,17,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,18,54,0,0,21,83,84,17,17,17,17,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,21,84,17,17,17,17,17,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,21,84,17,17,17,17,17,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,0,21,84,17,17,17,17,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,0,21,84,17,17,17,17,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,54,0,21,83,83,83,84,17,17,17,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,54,0,21,83,83,83,84,17,17,17,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,0,0,0,0,0,0,0,0,0,0,0,21,83,83,83,84,17,17,17,17,17,17,0,0,0,0,0,0,
|
0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,18,19,54,0,0,0,0,0,0,0,0,0,0,0,0,0,21,83,83,83,84,17,17,17,17,17,17,0,0,0,0,0,0,
|
||||||
0,0,0,17,17,17,17,17,17,17,17,17,17,17,18,19,19,54,0,0,0,0,0,0,0,0,21,83,83,83,83,83,83,84,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,
|
0,0,0,17,17,17,17,17,17,17,17,17,17,17,18,19,19,54,0,0,0,0,0,0,0,0,21,83,83,83,83,83,83,84,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,
|
||||||
0,17,17,17,17,17,17,17,17,17,17,18,19,19,54,0,0,0,21,83,83,83,83,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,
|
0,17,17,17,17,17,17,17,17,17,17,18,19,19,54,0,0,0,21,83,83,83,83,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
17,17,17,17,17,17,18,19,19,19,19,54,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,
|
17,17,17,17,17,17,18,19,19,19,19,54,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
17,17,18,19,19,19,54,0,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
17,17,18,19,19,19,54,0,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
19,19,54,0,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
19,19,54,0,0,0,21,83,83,83,84,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,21,84,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
0,0,0,0,0,21,84,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="3" name="Objects" width="50" height="50">
|
<layer id="3" name="Objects" width="50" height="50">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
0,0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,365,430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,365,430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,397,0,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,397,0,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,303,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,366,366,
|
0,0,303,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,366,366,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,0,397,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,0,397,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,397,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,397,0,0,
|
||||||
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,199,198,198,198,198,198,199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,368,0,0,
|
0,0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,199,198,198,198,198,198,199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,368,0,0,
|
||||||
0,365,366,366,430,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,0,0,303,0,0,0,0,0,0,397,0,0,
|
0,365,366,366,430,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,0,0,303,0,0,0,0,0,0,397,0,0,
|
||||||
0,397,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,237,0,0,0,0,0,0,0,0,397,0,0,
|
0,397,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,237,0,0,0,0,0,0,0,0,397,0,0,
|
||||||
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,265,266,266,266,267,266,266,266,266,266,267,266,266,266,268,0,0,0,0,0,111,0,0,0,0,0,0,0,0,397,0,0,
|
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,265,266,266,266,267,266,266,266,266,266,267,266,266,266,268,0,0,0,0,0,111,0,0,0,0,0,0,0,0,397,0,0,
|
||||||
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,365,366,430,0,0,
|
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,365,366,430,0,0,
|
||||||
0,397,0,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,303,0,
|
0,397,0,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,197,198,198,198,199,198,198,198,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,303,0,
|
||||||
303,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,265,266,266,266,267,266,266,290,266,266,267,266,266,266,268,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
303,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,265,266,266,266,267,266,266,290,266,266,267,266,266,266,268,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
||||||
0,368,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,197,198,198,198,199,198,198,322,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
0,368,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,197,198,198,198,199,198,198,322,198,198,199,198,198,198,200,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
||||||
0,397,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,77,0,301,302,0,0,0,397,0,0,0,0,
|
0,397,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,77,0,301,302,0,0,0,397,0,0,0,0,
|
||||||
0,397,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
0,397,0,193,194,195,194,194,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,397,0,0,0,0,
|
||||||
0,397,0,193,194,195,194,290,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,399,0,97,98,98,
|
0,397,0,193,194,195,194,290,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,399,0,97,98,98,
|
||||||
0,397,0,193,194,195,194,322,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,97,98,98,74,0,0,
|
0,397,0,193,194,195,194,322,194,195,194,196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,97,98,98,74,0,0,
|
||||||
0,397,301,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,97,74,0,0,0,0,0,
|
0,397,301,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,97,74,0,0,0,0,0,
|
||||||
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237,109,46,46,46,46,46,46,46,46,46,46,46,46,46,110,0,0,97,98,74,0,0,0,0,0,0,
|
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237,109,46,46,46,46,46,46,46,46,46,46,46,46,46,110,0,0,97,98,74,0,0,0,0,0,0,
|
||||||
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,0,0,301,302,0,0,0,0,0,97,74,0,0,0,0,0,0,0,0,
|
0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,0,0,301,302,0,0,0,0,0,97,74,0,0,0,0,0,0,0,0,
|
||||||
0,429,366,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,
|
0,429,366,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,397,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,97,74,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,397,0,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,97,74,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,41,162,
|
0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,41,162,
|
||||||
0,301,302,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,
|
0,301,302,397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,
|
||||||
0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,0,0,
|
0,0,0,397,0,0,0,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,0,0,
|
||||||
0,0,0,397,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,163,0,0,0,0,0,
|
0,0,0,397,0,0,0,0,0,0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,163,0,0,0,0,0,
|
||||||
0,0,0,399,0,303,97,98,98,98,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,0,0,301,302,0,
|
0,0,0,399,0,303,97,98,98,98,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,163,0,0,0,301,302,0,
|
||||||
0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,163,0,0,0,0,0,0,0,0,
|
0,0,0,97,98,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,163,0,0,0,0,0,0,0,0,
|
||||||
0,97,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,163,0,0,0,0,0,0,0,0,0,0,0,
|
0,97,98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,163,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,162,162,162,162,162,162,162,163,0,0,0,0,0,0,0,0,0,0,0,0,
|
98,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,162,162,162,162,162,162,162,163,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,162,162,163,0,0,301,302,0,0,0,0,0,0,0,0,303,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,162,162,163,0,0,301,302,0,0,0,0,0,0,0,0,303,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,41,162,162,162,162,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,41,162,162,162,162,163,0,0,0,0,0,0,0,303,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
0,0,0,0,0,0,0,0,41,162,162,162,162,163,0,0,0,0,0,0,0,303,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="4" name="Objects1" width="50" height="50">
|
<layer id="4" name="Objects1" width="50" height="50">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,365,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,365,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,298,299,300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,298,299,300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,330,331,332,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,330,331,332,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,363,364,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,363,364,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,385,386,387,0,354,0,0,0,354,0,385,386,387,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,385,386,387,0,354,0,0,0,354,0,385,386,387,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,104,105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,104,105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,385,386,387,0,0,135,0,137,0,0,385,386,387,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,385,386,387,0,0,135,0,137,0,0,385,386,387,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,385,386,387,0,0,0,0,0,0,0,0,0,229,301,302,230,231,230,230,230,230,230,231,303,230,230,232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,385,386,387,0,0,0,0,0,0,0,0,0,229,301,302,230,231,230,230,230,230,230,231,303,230,230,232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,257,258,259,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,257,258,259,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,354,0,289,0,291,0,354,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,354,0,289,0,291,0,354,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,289,0,291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,289,0,291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,302,226,227,226,226,226,227,226,228,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,302,226,227,226,226,226,227,226,228,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="6" name="Above" width="50" height="50">
|
<layer id="6" name="Above" width="50" height="50">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,333,335,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,333,335,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,
|
0,0,0,0,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,333,334,334,
|
0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,333,334,334,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,261,263,264,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,261,263,264,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,261,262,262,262,262,293,327,296,262,262,262,262,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,261,262,262,262,262,293,327,296,262,262,262,262,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,261,293,326,326,326,326,325,327,328,326,326,326,326,296,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,336,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,261,293,326,326,326,326,325,327,328,326,326,326,326,296,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,336,0,0,
|
||||||
0,333,334,334,335,0,0,0,0,0,0,0,0,0,0,0,0,292,293,325,326,326,326,326,325,327,328,326,326,326,326,328,296,297,0,0,0,0,173,0,271,0,0,0,0,0,0,0,0,0,
|
0,333,334,334,335,0,0,0,0,0,0,0,0,0,0,0,0,292,293,325,326,326,326,326,325,327,328,326,326,326,326,328,296,297,0,0,0,0,173,0,271,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,356,325,325,326,326,326,326,357,359,360,326,326,326,326,328,328,361,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,356,325,325,326,326,326,326,357,359,360,326,326,326,326,328,328,361,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,356,325,357,358,358,358,358,389,0,392,358,358,358,358,360,328,361,0,0,0,0,79,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,356,325,357,358,358,358,358,389,0,392,358,358,358,358,360,328,361,0,0,0,0,79,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,356,357,389,0,0,0,0,0,0,0,0,0,0,0,392,360,361,0,0,0,0,0,0,0,0,0,0,0,333,334,335,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,356,357,389,0,0,0,0,0,0,0,0,0,0,0,392,360,361,0,0,0,0,0,0,0,0,0,0,0,333,334,335,0,0,
|
||||||
0,0,0,0,0,261,262,262,262,264,0,269,270,0,0,0,0,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,392,393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,
|
0,0,0,0,0,261,262,262,262,264,0,269,270,0,0,0,0,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,392,393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,
|
||||||
271,0,0,261,262,293,326,326,326,296,262,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
271,0,0,261,262,293,326,326,326,296,262,264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,336,292,293,326,325,326,326,326,328,326,296,297,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,336,292,293,326,325,326,326,326,328,326,296,297,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,356,325,326,357,358,358,358,360,326,328,361,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,
|
0,0,356,325,326,357,358,358,358,360,326,328,361,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,
|
||||||
0,0,356,357,358,389,0,0,0,392,358,360,361,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,356,357,358,389,0,0,0,392,358,360,361,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,388,389,0,0,0,0,0,0,0,392,393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,43,43,43,43,43,43,0,0,0,0,0,0,0,0,336,0,0,0,0,
|
0,0,388,389,0,0,0,0,0,0,0,392,393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,43,43,43,43,43,43,0,0,0,0,0,0,0,0,336,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,8,2147483656,9,1073741833,3221225545,43,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,8,2147483656,9,1073741833,3221225545,43,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,0,0,0,0,0,43,43,43,43,43,43,43,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,0,0,0,0,0,0,43,43,43,43,43,43,43,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,13,14,14,14,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,13,14,14,14,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,333,334,335,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,333,334,335,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,269,270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,336,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,
|
0,0,0,336,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,269,270,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
</map>
|
</map>
|
||||||
|
|
|
@ -22,6 +22,7 @@ using MLEM.Ui;
|
||||||
using MLEM.Ui.Elements;
|
using MLEM.Ui.Elements;
|
||||||
using MLEM.Ui.Style;
|
using MLEM.Ui.Style;
|
||||||
using MonoGame.Extended.Tiled;
|
using MonoGame.Extended.Tiled;
|
||||||
|
using MonoGame.Extended.ViewportAdapters;
|
||||||
|
|
||||||
namespace Sandbox {
|
namespace Sandbox {
|
||||||
public class GameImpl : MlemGame {
|
public class GameImpl : MlemGame {
|
||||||
|
@ -119,13 +120,6 @@ namespace Sandbox {
|
||||||
Console.WriteLine(vec + " -> " + dir);
|
Console.WriteLine(vec + " -> " + dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
var copy = obj.DeepCopy();
|
|
||||||
Console.WriteLine(copy);
|
|
||||||
|
|
||||||
var intoCopy = new Test(Vector2.One, "test") {OtherTest = new Test(Vector2.One, "other")};
|
|
||||||
obj.DeepCopyInto(intoCopy);
|
|
||||||
Console.WriteLine(intoCopy);
|
|
||||||
|
|
||||||
var writer = new StringWriter();
|
var writer = new StringWriter();
|
||||||
this.Content.GetJsonSerializer().Serialize(writer, obj);
|
this.Content.GetJsonSerializer().Serialize(writer, obj);
|
||||||
//Console.WriteLine(writer.ToString());
|
//Console.WriteLine(writer.ToString());
|
||||||
|
@ -239,7 +233,7 @@ namespace Sandbox {
|
||||||
par.OnDrawn = (e, time, batch, a) => batch.DrawRectangle(e.DisplayArea.ToExtended(), Color.Red);
|
par.OnDrawn = (e, time, batch, a) => batch.DrawRectangle(e.DisplayArea.ToExtended(), Color.Red);
|
||||||
this.UiSystem.Add("Load", loadGroup);*/
|
this.UiSystem.Add("Load", loadGroup);*/
|
||||||
|
|
||||||
var spillPanel = new Panel(Anchor.Center, new Vector2(100), Vector2.Zero);
|
/*var spillPanel = new Panel(Anchor.Center, new Vector2(100), Vector2.Zero);
|
||||||
var squishingGroup = spillPanel.AddChild(new SquishingGroup(Anchor.TopLeft, Vector2.One));
|
var squishingGroup = spillPanel.AddChild(new SquishingGroup(Anchor.TopLeft, Vector2.One));
|
||||||
squishingGroup.AddChild(new Button(Anchor.TopLeft, new Vector2(30), "TL") {
|
squishingGroup.AddChild(new Button(Anchor.TopLeft, new Vector2(30), "TL") {
|
||||||
OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D1),
|
OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D1),
|
||||||
|
@ -266,7 +260,60 @@ namespace Sandbox {
|
||||||
e.SetAreaDirty();
|
e.SetAreaDirty();
|
||||||
}
|
}
|
||||||
}).SetData("Ref", "Main");
|
}).SetData("Ref", "Main");
|
||||||
this.UiSystem.Add("SpillTest", spillPanel);
|
this.UiSystem.Add("SpillTest", spillPanel);*/
|
||||||
|
|
||||||
|
var regularFont = spriteFont.Font;
|
||||||
|
var genericFont = spriteFont;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
var pos = new Vector2(100, 20);
|
||||||
|
var scale = 1F;
|
||||||
|
var origin = Vector2.Zero;
|
||||||
|
var rotation = 0F;
|
||||||
|
var effects = SpriteEffects.None;
|
||||||
|
|
||||||
|
this.OnDraw += (g, time) => {
|
||||||
|
const string testString = "This is a\ntest string\n\twith long lines.\nLet's write some more stuff. Let's\r\nsplit lines weirdly.";
|
||||||
|
if (Input.IsKeyPressed(Keys.I)) {
|
||||||
|
index++;
|
||||||
|
if (index == 1) {
|
||||||
|
scale = 2;
|
||||||
|
} else if (index == 2) {
|
||||||
|
origin = new Vector2(15, 15);
|
||||||
|
} else if (index == 3) {
|
||||||
|
rotation = 0.25F;
|
||||||
|
} else if (index == 4) {
|
||||||
|
effects = SpriteEffects.FlipHorizontally;
|
||||||
|
} else if (index == 5) {
|
||||||
|
effects = SpriteEffects.FlipVertically;
|
||||||
|
} else if (index == 6) {
|
||||||
|
effects = SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SpriteBatch.Begin();
|
||||||
|
if (Input.IsKeyDown(Keys.LeftShift)) {
|
||||||
|
this.SpriteBatch.DrawString(regularFont, testString, pos, Color.Red, rotation, origin, scale, effects, 0);
|
||||||
|
} else {
|
||||||
|
genericFont.DrawString(this.SpriteBatch, testString, pos, Color.Green, rotation, origin, scale, effects, 0);
|
||||||
|
}
|
||||||
|
this.SpriteBatch.End();
|
||||||
|
};
|
||||||
|
|
||||||
|
var viewport = new BoxingViewportAdapter(this.Window, this.GraphicsDevice, 1280, 720);
|
||||||
|
var newPanel = new Panel(Anchor.TopLeft, new Vector2(200, 100), new Vector2(10, 10));
|
||||||
|
newPanel.AddChild(new Button(Anchor.TopLeft, new Vector2(100, 20), "Text", "Tooltip text"));
|
||||||
|
this.UiSystem.Add("Panel", newPanel);
|
||||||
|
|
||||||
|
var keybindPanel = new Panel(Anchor.BottomRight, new Vector2(130, 150), new Vector2(5));
|
||||||
|
for (var i = 0; i < 15; i++) {
|
||||||
|
var button = keybindPanel.AddChild(new Button(default, default, i.ToString()));
|
||||||
|
button.Anchor = Anchor.AutoInline;
|
||||||
|
button.Padding = new Padding(0.5F);
|
||||||
|
button.SetHeightBasedOnChildren = false;
|
||||||
|
button.Size = new Vector2(30, 50);
|
||||||
|
}
|
||||||
|
this.UiSystem.Add("Keybinds", keybindPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DoUpdate(GameTime gameTime) {
|
protected override void DoUpdate(GameTime gameTime) {
|
||||||
|
@ -276,13 +323,13 @@ namespace Sandbox {
|
||||||
|
|
||||||
var delta = this.InputHandler.ScrollWheel - this.InputHandler.LastScrollWheel;
|
var delta = this.InputHandler.ScrollWheel - this.InputHandler.LastScrollWheel;
|
||||||
if (delta != 0) {
|
if (delta != 0) {
|
||||||
this.camera.Zoom(0.1F * Math.Sign(delta), this.InputHandler.MousePosition.ToVector2());
|
this.camera.Zoom(0.1F * Math.Sign(delta), this.InputHandler.ViewportMousePosition.ToVector2());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (Input.InputsDown.Length > 0)
|
/*if (Input.InputsDown.Length > 0)
|
||||||
Console.WriteLine("Down: " + string.Join(", ", Input.InputsDown));
|
Console.WriteLine("Down: " + string.Join(", ", Input.InputsDown));*/
|
||||||
if (Input.InputsPressed.Length > 0)
|
if (Input.InputsPressed.Length > 0)
|
||||||
Console.WriteLine("Pressed: " + string.Join(", ", Input.InputsPressed));*/
|
Console.WriteLine("Pressed: " + string.Join(", ", Input.InputsPressed));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DoDraw(GameTime gameTime) {
|
protected override void DoDraw(GameTime gameTime) {
|
||||||
|
@ -307,7 +354,6 @@ namespace Sandbox {
|
||||||
public Direction2 Dir { get; set; }
|
public Direction2 Dir { get; set; }
|
||||||
public Test OtherTest;
|
public Test OtherTest;
|
||||||
|
|
||||||
[CopyConstructor]
|
|
||||||
public Test(Vector2 test, string test2) {
|
public Test(Vector2 test, string test2) {
|
||||||
Console.WriteLine("Constructed with " + test + ", " + test2);
|
Console.WriteLine("Constructed with " + test + ", " + test2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MLEM.Data\MLEM.Data.csproj" />
|
<ProjectReference Include="..\MLEM.Data\MLEM.Data.csproj" />
|
||||||
<ProjectReference Include="..\MLEM.Extended\MLEM.Extended.csproj" />
|
<ProjectReference Include="..\MLEM.Extended\MLEM.Extended.csproj" />
|
||||||
|
@ -12,15 +12,16 @@
|
||||||
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
<ProjectReference Include="..\MLEM.Ui\MLEM.Ui.csproj" />
|
||||||
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
<ProjectReference Include="..\MLEM\MLEM.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
|
||||||
<PackageReference Include="MonoGame.Extended.Content.Pipeline" Version="3.8.0" />
|
<PackageReference Include="MonoGame.Extended.Content.Pipeline" Version="3.8.0" />
|
||||||
<PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0" />
|
<PackageReference Include="MonoGame.Extended.Tiled" Version="3.8.0" />
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
||||||
<PackageReference Include="FontStashSharp.MonoGame" Version="1.0.4" />
|
<PackageReference Include="FontStashSharp.MonoGame" Version="1.0.4" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MonoGameContentReference Include="Content\Content.mgcb" />
|
<MonoGameContentReference Include="Content\Content.mgcb" />
|
||||||
<Content Include="Content\*\**" />
|
<Content Include="Content\*\**" />
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
@ -38,33 +37,6 @@ namespace Tests {
|
||||||
Assert.AreEqual(this.testObject, read);
|
Assert.AreEqual(this.testObject, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestCopy() {
|
|
||||||
var copy = this.testObject.Copy();
|
|
||||||
Assert.AreEqual(this.testObject, copy);
|
|
||||||
Assert.AreSame(this.testObject.OtherTest, copy.OtherTest);
|
|
||||||
|
|
||||||
var deepCopy = this.testObject.DeepCopy();
|
|
||||||
Assert.AreEqual(this.testObject, deepCopy);
|
|
||||||
Assert.AreNotSame(this.testObject.OtherTest, deepCopy.OtherTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestCopySpeed() {
|
|
||||||
const int count = 1000000;
|
|
||||||
var stopwatch = Stopwatch.StartNew();
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
this.testObject.Copy();
|
|
||||||
stopwatch.Stop();
|
|
||||||
TestContext.WriteLine($"Copy took {stopwatch.Elapsed.TotalMilliseconds / count * 1000000}ns on average");
|
|
||||||
|
|
||||||
stopwatch.Restart();
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
this.testObject.DeepCopy();
|
|
||||||
stopwatch.Stop();
|
|
||||||
TestContext.WriteLine($"DeepCopy took {stopwatch.Elapsed.TotalMilliseconds / count * 1000000}ns on average");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDynamicEnum() {
|
public void TestDynamicEnum() {
|
||||||
var flags = new TestEnum[100];
|
var flags = new TestEnum[100];
|
||||||
|
@ -124,8 +96,7 @@ namespace Tests {
|
||||||
public Direction2 Dir { get; set; }
|
public Direction2 Dir { get; set; }
|
||||||
public TestObject OtherTest;
|
public TestObject OtherTest;
|
||||||
|
|
||||||
public TestObject(Vector2 test, string test2) {
|
public TestObject(Vector2 test, string test2) {}
|
||||||
}
|
|
||||||
|
|
||||||
protected bool Equals(TestObject other) {
|
protected bool Equals(TestObject other) {
|
||||||
return this.Vec.Equals(other.Vec) && this.Point.Equals(other.Point) && Equals(this.OtherTest, other.OtherTest) && this.Dir == other.Dir;
|
return this.Vec.Equals(other.Vec) && this.Point.Equals(other.Point) && Equals(this.OtherTest, other.OtherTest) && this.Dir == other.Dir;
|
||||||
|
@ -143,8 +114,7 @@ namespace Tests {
|
||||||
|
|
||||||
private class TestEnum : DynamicEnum {
|
private class TestEnum : DynamicEnum {
|
||||||
|
|
||||||
public TestEnum(string name, BigInteger value) : base(name, value) {
|
public TestEnum(string name, BigInteger value) : base(name, value) {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,10 +147,10 @@ namespace Tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareSizes($"This is a very simple{GenericFont.Nbsp}test string");
|
CompareSizes($"This is a very simple{GenericFont.Nbsp}test string");
|
||||||
CompareSizes($"This is a very simple{GenericFont.OneEmSpace}test string");
|
CompareSizes($"This is a very simple{GenericFont.Emsp}test string");
|
||||||
CompareSizes($"This is a very simple{GenericFont.Zwsp}test string");
|
CompareSizes($"This is a very simple{GenericFont.Zwsp}test string");
|
||||||
|
|
||||||
Assert.AreEqual(new Vector2(this.font.LineHeight, this.font.LineHeight), this.font.MeasureString(GenericFont.OneEmSpace.ToCachedString()));
|
Assert.AreEqual(new Vector2(this.font.LineHeight, this.font.LineHeight), this.font.MeasureString(GenericFont.Emsp.ToCachedString()));
|
||||||
Assert.AreEqual(new Vector2(0, this.font.LineHeight), this.font.MeasureString(GenericFont.Zwsp.ToCachedString()));
|
Assert.AreEqual(new Vector2(0, this.font.LineHeight), this.font.MeasureString(GenericFont.Zwsp.ToCachedString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ namespace Tests {
|
||||||
|
|
||||||
public RawContentManager RawContent { get; private set; }
|
public RawContentManager RawContent { get; private set; }
|
||||||
|
|
||||||
private TestGame() {
|
private TestGame() {}
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadContent() {
|
protected override void LoadContent() {
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<VSTestLogger>nunit</VSTestLogger>
|
<VSTestLogger>nunit</VSTestLogger>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
<ProjectReference Include="..\MLEM.Startup\MLEM.Startup.csproj" />
|
||||||
<ProjectReference Include="..\MLEM.Data\MLEM.Data.csproj" />
|
<ProjectReference Include="..\MLEM.Data\MLEM.Data.csproj" />
|
||||||
|
@ -14,18 +14,19 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
|
||||||
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
|
||||||
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
|
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Content/**">
|
<Content Include="Content/**">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -80,8 +80,7 @@ namespace Tests {
|
||||||
Assert.AreEqual(170, packer4.PackedTexture.Height);
|
Assert.AreEqual(170, packer4.PackedTexture.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void StubResult(TextureRegion region) {
|
private static void StubResult(TextureRegion region) {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
#tool docfx.console&version=2.58.9
|
#tool docfx.console&version=2.58.9
|
||||||
|
|
||||||
// this is the upcoming version, for prereleases
|
// this is the upcoming version, for prereleases
|
||||||
var version = Argument("version", "5.2.0");
|
var version = Argument("version", "5.3.0");
|
||||||
var target = Argument("target", "Default");
|
var target = Argument("target", "Default");
|
||||||
var branch = Argument("branch", "main");
|
var branch = Argument("branch", "main");
|
||||||
var config = Argument("configuration", "Release");
|
var config = Argument("configuration", "Release");
|
||||||
|
|
Loading…
Reference in a new issue