mirror of
https://gitlab.acidiclight.dev/sociallydistant/sociallydistant.git
synced 2025-01-22 09:31:47 -05:00
Fix various platform issues and slightly improve UI
* Fix crash on lower screen resolutions when clicking on Terminal Mouse coordinates were not being scaled from screenspace into canvas space, resulting in a crash when clicking on the Terminal. Also add documentation for internal VirtualScreen implementation, and define dynamic properties for CanvasWidth and CanvasHeight in the UI system. Issue: #13 Signed-off-by: Ritchie Frodomar <alkalinethunder@gmail.com> * Remove old GuiService virtual screen and document IVirtualScreen Whoever wrote that old code was high, fuck... wait a minute... Signed-off-by: Ritchie Frodomar <alkalinethunder@gmail.com> * Fix various errors after emergency rebase * Remove Rider caches * Attempt to enable Wayland support * Add support for enabling/disabling Wayland support on Linux * Move SettingsManager to GameApplication so settings can be loaded before the game engine fully boots. * Test commit. Signed-off-by: Ritchie Frodomar <alkalinethunder@gmail.com> * Move Terminals to their own tile * Add support for getting CPU name on Windows via registry * Add support for disabling background blur * Fix window hints not being restored when switching between main tool tabs * Testing the DCO acknowledgement job Signed-off-by: Ritchie Frodomar <alkalinethunder@gmail.com>
This commit is contained in:
parent
7f8f7dbf42
commit
75c8b5432c
1256 changed files with 7908 additions and 7874 deletions
0
.config/dotnet-tools.json
Normal file → Executable file
0
.config/dotnet-tools.json
Normal file → Executable file
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
|
# Rider caches
|
||||||
|
.idea/
|
||||||
|
|
||||||
# docfx
|
# docfx
|
||||||
api/
|
api/
|
||||||
public/
|
public/
|
||||||
|
|
0
.gitlab-ci.yml
Normal file → Executable file
0
.gitlab-ci.yml
Normal file → Executable file
0
Assets/Assets/Core/WebSites.meta
Normal file → Executable file
0
Assets/Assets/Core/WebSites.meta
Normal file → Executable file
0
Assets/Assets/Core/WebSites/404.prefab
Normal file → Executable file
0
Assets/Assets/Core/WebSites/404.prefab
Normal file → Executable file
0
Assets/Assets/Core/WebSites/404.prefab.meta
Normal file → Executable file
0
Assets/Assets/Core/WebSites/404.prefab.meta
Normal file → Executable file
0
Assets/Assets/Core/WebSites/TheMissingPage.asset
Normal file → Executable file
0
Assets/Assets/Core/WebSites/TheMissingPage.asset
Normal file → Executable file
0
Assets/Assets/Core/WebSites/TheMissingPage.asset.meta
Normal file → Executable file
0
Assets/Assets/Core/WebSites/TheMissingPage.asset.meta
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.asset
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.asset
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.asset.meta
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.asset.meta
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.prefab
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.prefab
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.prefab.meta
Normal file → Executable file
0
Assets/Assets/Main/Websites/NewCipherToday.prefab.meta
Normal file → Executable file
0
Assets/Editor/CustomImporters/ArticleImporter.cs
Normal file → Executable file
0
Assets/Editor/CustomImporters/ArticleImporter.cs
Normal file → Executable file
0
Assets/Scripts/UI/Applications/WebBrowser/ItsAllFuckingGone.cs
Normal file → Executable file
0
Assets/Scripts/UI/Applications/WebBrowser/ItsAllFuckingGone.cs
Normal file → Executable file
0
Assets/Scripts/UI/Applications/WebBrowser/ItsAllFuckingGone.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Applications/WebBrowser/ItsAllFuckingGone.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Shell/ShellNavigationLink.cs
Normal file → Executable file
0
Assets/Scripts/UI/Shell/ShellNavigationLink.cs
Normal file → Executable file
0
Assets/Scripts/UI/Shell/ShellNavigationLink.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Shell/ShellNavigationLink.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News.meta
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News.meta
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News/NewsWebSite.cs
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News/NewsWebSite.cs
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News/NewsWebSite.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Websites/News/NewsWebSite.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/SocialPost.prefab
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/SocialPost.prefab
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/SocialPost.prefab.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/SocialPost.prefab.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/WebSearchResult.prefab
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/WebSearchResult.prefab
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/WebSearchResult.prefab.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Prefabs/WebSearchResult.prefab.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Settings/SocialPostWidget.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Settings/SocialPostWidget.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Settings/SocialPostWidget.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/Settings/SocialPostWidget.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/SocialPostWidgetController.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/SocialPostWidgetController.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/SocialPostWidgetController.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/SocialPostWidgetController.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/WebSearchResultWidgetController.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/WebSearchResultWidgetController.cs
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/WebSearchResultWidgetController.cs.meta
Normal file → Executable file
0
Assets/Scripts/UI/Widgets/WebSearchResultWidgetController.cs.meta
Normal file → Executable file
0
CONTRIBUTING.md
Normal file → Executable file
0
CONTRIBUTING.md
Normal file → Executable file
0
LICENSE
Normal file → Executable file
0
LICENSE
Normal file → Executable file
0
README.md
Normal file → Executable file
0
README.md
Normal file → Executable file
0
mgfxc-wine-setup.sh
Normal file → Executable file
0
mgfxc-wine-setup.sh
Normal file → Executable file
13
src/.idea/.idea.sociallydistant/.idea/.gitignore
vendored
13
src/.idea/.idea.sociallydistant/.idea/.gitignore
vendored
|
@ -1,13 +0,0 @@
|
||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Rider ignored files
|
|
||||||
/contentModel.xml
|
|
||||||
/.idea.sociallydistant.iml
|
|
||||||
/projectSettingsUpdater.xml
|
|
||||||
/modules.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
|
@ -1 +0,0 @@
|
||||||
sociallydistant
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
|
||||||
</project>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="UserContentModel">
|
|
||||||
<attachedFolders>
|
|
||||||
<Path>../docs</Path>
|
|
||||||
</attachedFolders>
|
|
||||||
<explicitIncludes />
|
|
||||||
<explicitExcludes />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
0
src/AcidicGUI/AcidicGUI.csproj
Normal file → Executable file
0
src/AcidicGUI/AcidicGUI.csproj
Normal file → Executable file
0
src/AcidicGUI/ColorHelpers.cs
Normal file → Executable file
0
src/AcidicGUI/ColorHelpers.cs
Normal file → Executable file
0
src/AcidicGUI/CustomProperties/CanvasAnchors.cs
Normal file → Executable file
0
src/AcidicGUI/CustomProperties/CanvasAnchors.cs
Normal file → Executable file
0
src/AcidicGUI/CustomProperties/CustomPropertyObject.cs
Normal file → Executable file
0
src/AcidicGUI/CustomProperties/CustomPropertyObject.cs
Normal file → Executable file
2
src/AcidicGUI/CustomProperties/FlexPanelProperties.cs
Normal file → Executable file
2
src/AcidicGUI/CustomProperties/FlexPanelProperties.cs
Normal file → Executable file
|
@ -14,7 +14,7 @@ public sealed class FlexPanelProperties : CustomPropertyObject
|
||||||
get => proportionalValue;
|
get => proportionalValue;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
proportionalValue = MathHelper.Clamp(value, 0f, 1f);
|
proportionalValue = Math.Max(0, value);
|
||||||
Widget.InvalidateLayout();
|
Widget.InvalidateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
0
src/AcidicGUI/CustomProperties/StructProperty.cs
Normal file → Executable file
0
src/AcidicGUI/CustomProperties/StructProperty.cs
Normal file → Executable file
18
src/AcidicGUI/Effects/IEffect.cs
Normal file → Executable file
18
src/AcidicGUI/Effects/IEffect.cs
Normal file → Executable file
|
@ -1,11 +1,9 @@
|
||||||
using Microsoft.Xna.Framework;
|
namespace AcidicGUI.Effects;
|
||||||
|
|
||||||
namespace AcidicGUI.Effects;
|
public interface IEffect
|
||||||
|
{
|
||||||
public interface IEffect
|
int PassesCount { get; }
|
||||||
{
|
|
||||||
int PassesCount { get; }
|
void Use(int pass);
|
||||||
|
void UpdateOpacity(float opacity);
|
||||||
void Use(int pass);
|
|
||||||
void UpdateWidgetParameters(float opacity, Matrix widgetTransform);
|
|
||||||
}
|
}
|
0
src/AcidicGUI/Effects/IWidgetEffect.cs
Normal file → Executable file
0
src/AcidicGUI/Effects/IWidgetEffect.cs
Normal file → Executable file
0
src/AcidicGUI/Events/FocusEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/FocusEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/GuiEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/GuiEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragEndHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragEndHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragStartHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IDragStartHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IGainFocusHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IGainFocusHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyCharHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyCharHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IKeyUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/ILoseFocusHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/ILoseFocusHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseClickHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseClickHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseEnterHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseEnterHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseLeaveHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseLeaveHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseMoveHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseMoveHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseScrollHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseScrollHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IMouseUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyCharHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyCharHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyDownHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IPreviewKeyUpHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IUpdateHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/IUpdateHandler.cs
Normal file → Executable file
0
src/AcidicGUI/Events/KeyCharEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/KeyCharEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/KeyEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/KeyEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/ModifierKeys.cs
Normal file → Executable file
0
src/AcidicGUI/Events/ModifierKeys.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseButtonEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseButtonEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseMoveEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseMoveEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseScrollEvent.cs
Normal file → Executable file
0
src/AcidicGUI/Events/MouseScrollEvent.cs
Normal file → Executable file
901
src/AcidicGUI/GuiManager.cs
Normal file → Executable file
901
src/AcidicGUI/GuiManager.cs
Normal file → Executable file
|
@ -1,446 +1,457 @@
|
||||||
using AcidicGUI.Animation;
|
using AcidicGUI.Events;
|
||||||
using AcidicGUI.Events;
|
using AcidicGUI.Layout;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Rendering;
|
||||||
using AcidicGUI.Rendering;
|
using AcidicGUI.TextRendering;
|
||||||
using AcidicGUI.TextRendering;
|
using AcidicGUI.VisualStyles;
|
||||||
using AcidicGUI.VisualStyles;
|
using AcidicGUI.Widgets;
|
||||||
using AcidicGUI.Widgets;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using Microsoft.Xna.Framework.Input;
|
|
||||||
|
namespace AcidicGUI;
|
||||||
namespace AcidicGUI;
|
|
||||||
|
public sealed class GuiManager : IFontFamilyProvider
|
||||||
public sealed class GuiManager : IFontFamilyProvider
|
{
|
||||||
{
|
private readonly IGuiContext context;
|
||||||
private readonly IGuiContext context;
|
private readonly Widget.TopLevelCollection topLevels;
|
||||||
private readonly Widget.TopLevelCollection topLevels;
|
private readonly GuiRenderer renderer;
|
||||||
private readonly GuiRenderer renderer;
|
private readonly FallbackVisualStyle fallbackVisualStyle = new FallbackVisualStyle();
|
||||||
private readonly FallbackVisualStyle fallbackVisualStyle = new FallbackVisualStyle();
|
private MouseButton previousMouseButtonFlags;
|
||||||
private MouseButton previousMouseButtonFlags;
|
private ButtonState leftControl;
|
||||||
private ButtonState leftControl;
|
private ButtonState rightControl;
|
||||||
private ButtonState rightControl;
|
private ButtonState leftShift;
|
||||||
private ButtonState leftShift;
|
private ButtonState rightShift;
|
||||||
private ButtonState rightShift;
|
private ButtonState leftAlt;
|
||||||
private ButtonState leftAlt;
|
private ButtonState rightAlt;
|
||||||
private ButtonState rightAlt;
|
|
||||||
|
|
||||||
|
private IVisualStyle? visualStyleOverride;
|
||||||
private IVisualStyle? visualStyleOverride;
|
private int screenWidth;
|
||||||
private int screenWidth;
|
private int screenHeight;
|
||||||
private int screenHeight;
|
private bool isRendering;
|
||||||
private bool isRendering;
|
private Widget? hoveredWidget;
|
||||||
private Widget? hoveredWidget;
|
private Widget? widgetBeingDragged;
|
||||||
private Widget? widgetBeingDragged;
|
private Widget? keyboardFocus;
|
||||||
private Widget? keyboardFocus;
|
private MouseState? previousMouseState;
|
||||||
private MouseState? previousMouseState;
|
private bool reachedFirstUpdate;
|
||||||
private bool reachedFirstUpdate;
|
|
||||||
|
public bool IsRendering => isRendering;
|
||||||
public bool IsRendering => isRendering;
|
public IOrderedCollection<Widget> TopLevels => topLevels;
|
||||||
public IOrderedCollection<Widget> TopLevels => topLevels;
|
|
||||||
|
public GuiManager(IGuiContext context, IVisualStyle? globalStyle = null)
|
||||||
public GuiManager(IGuiContext context, IVisualStyle? globalStyle = null)
|
{
|
||||||
{
|
this.context = context;
|
||||||
this.context = context;
|
topLevels = new Widget.TopLevelCollection(this);
|
||||||
topLevels = new Widget.TopLevelCollection(this);
|
renderer = new GuiRenderer(context);
|
||||||
renderer = new GuiRenderer(context);
|
|
||||||
|
visualStyleOverride = globalStyle;
|
||||||
visualStyleOverride = globalStyle;
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
public bool IsFocused(Widget widget)
|
/// Invalidates the geometry of all interface elements recursively. Use this when changing a global UI setting that affects how all widgets render.
|
||||||
{
|
/// Note: This is expensive. That should be obvious. So do not call it every frame.
|
||||||
return widget == keyboardFocus;
|
/// </summary>
|
||||||
}
|
public void InvalidateAllGeometry()
|
||||||
|
{
|
||||||
public void SetFocusedWidget(Widget? widgetToFocus)
|
foreach (var toplevel in TopLevels)
|
||||||
{
|
{
|
||||||
if (widgetToFocus == keyboardFocus)
|
toplevel.InvalidateGeometry(true);
|
||||||
return;
|
}
|
||||||
|
}
|
||||||
var e = new FocusEvent(widgetToFocus);
|
|
||||||
|
public bool IsFocused(Widget widget)
|
||||||
if (keyboardFocus != null)
|
{
|
||||||
{
|
return widget == keyboardFocus;
|
||||||
Bubble<ILoseFocusHandler, FocusEvent>(keyboardFocus, e, x => x.OnFocusLost);
|
}
|
||||||
}
|
|
||||||
|
public void SetFocusedWidget(Widget? widgetToFocus)
|
||||||
keyboardFocus = widgetToFocus;
|
{
|
||||||
|
if (widgetToFocus == keyboardFocus)
|
||||||
if (keyboardFocus != null)
|
return;
|
||||||
{
|
|
||||||
Bubble<IGainFocusHandler, FocusEvent>(keyboardFocus, e, x => x.OnFocusGained);
|
var e = new FocusEvent(widgetToFocus);
|
||||||
}
|
|
||||||
}
|
if (keyboardFocus != null)
|
||||||
|
{
|
||||||
public void SendMouseButton(MouseButtonEventArgs e)
|
Bubble<ILoseFocusHandler, FocusEvent>(keyboardFocus, e, x => x.OnFocusLost);
|
||||||
{
|
}
|
||||||
var previousState = (previousMouseButtonFlags & e.Button) != 0
|
|
||||||
? ButtonState.Pressed
|
keyboardFocus = widgetToFocus;
|
||||||
: ButtonState.Released;
|
|
||||||
|
if (keyboardFocus != null)
|
||||||
HandleMouseButton(e.Button, previousState, e.ButtonState, e.Position, Point.Zero);
|
{
|
||||||
|
Bubble<IGainFocusHandler, FocusEvent>(keyboardFocus, e, x => x.OnFocusGained);
|
||||||
if (e.ButtonState == ButtonState.Pressed)
|
}
|
||||||
{
|
}
|
||||||
previousMouseButtonFlags = previousMouseButtonFlags | e.Button;
|
|
||||||
}
|
public void SendMouseButton(MouseButtonEventArgs e)
|
||||||
else
|
{
|
||||||
{
|
var previousState = (previousMouseButtonFlags & e.Button) != 0
|
||||||
previousMouseButtonFlags = previousMouseButtonFlags & ~e.Button;
|
? ButtonState.Pressed
|
||||||
}
|
: ButtonState.Released;
|
||||||
}
|
|
||||||
|
HandleMouseButton(e.Button, previousState, e.ButtonState, TranslateMousePosition(e.Position), Point.Zero);
|
||||||
public void SendCharacter(Keys key, char character)
|
|
||||||
{
|
if (e.ButtonState == ButtonState.Pressed)
|
||||||
var e = new KeyCharEvent(key, GetKeyModifiers(), character);
|
{
|
||||||
|
previousMouseButtonFlags = previousMouseButtonFlags | e.Button;
|
||||||
if (hoveredWidget != null)
|
}
|
||||||
{
|
else
|
||||||
Bubble<IPreviewKeyCharHandler, KeyCharEvent>(hoveredWidget, e, x => x.OnPreviewKeyChar);
|
{
|
||||||
}
|
previousMouseButtonFlags = previousMouseButtonFlags & ~e.Button;
|
||||||
|
}
|
||||||
if (keyboardFocus != null)
|
}
|
||||||
{
|
|
||||||
Bubble<IKeyCharHandler, KeyCharEvent>(keyboardFocus, e, x => x.OnKeyChar);
|
public void SendCharacter(Keys key, char character)
|
||||||
}
|
{
|
||||||
}
|
var e = new KeyCharEvent(key, GetKeyModifiers(), character);
|
||||||
|
|
||||||
private ModifierKeys GetKeyModifiers()
|
if (hoveredWidget != null)
|
||||||
{
|
{
|
||||||
var result = ModifierKeys.None;
|
Bubble<IPreviewKeyCharHandler, KeyCharEvent>(hoveredWidget, e, x => x.OnPreviewKeyChar);
|
||||||
|
}
|
||||||
if (leftControl == ButtonState.Pressed || rightControl == ButtonState.Pressed)
|
|
||||||
result |= ModifierKeys.Control;
|
if (keyboardFocus != null)
|
||||||
|
{
|
||||||
if (leftShift == ButtonState.Pressed || rightShift == ButtonState.Pressed)
|
Bubble<IKeyCharHandler, KeyCharEvent>(keyboardFocus, e, x => x.OnKeyChar);
|
||||||
result |= ModifierKeys.Shift;
|
}
|
||||||
|
}
|
||||||
if (leftAlt == ButtonState.Pressed || rightAlt == ButtonState.Pressed)
|
|
||||||
result |= ModifierKeys.Alt;
|
private ModifierKeys GetKeyModifiers()
|
||||||
|
{
|
||||||
return result;
|
var result = ModifierKeys.None;
|
||||||
}
|
|
||||||
|
if (leftControl == ButtonState.Pressed || rightControl == ButtonState.Pressed)
|
||||||
public void SendKey(Keys key, ButtonState state)
|
result |= ModifierKeys.Control;
|
||||||
{
|
|
||||||
switch (key)
|
if (leftShift == ButtonState.Pressed || rightShift == ButtonState.Pressed)
|
||||||
{
|
result |= ModifierKeys.Shift;
|
||||||
case Keys.LeftControl:
|
|
||||||
leftControl = state;
|
if (leftAlt == ButtonState.Pressed || rightAlt == ButtonState.Pressed)
|
||||||
break;
|
result |= ModifierKeys.Alt;
|
||||||
case Keys.RightControl:
|
|
||||||
rightControl = state;
|
return result;
|
||||||
break;
|
}
|
||||||
case Keys.LeftShift:
|
|
||||||
leftShift = state;
|
public void SendKey(Keys key, ButtonState state)
|
||||||
break;
|
{
|
||||||
case Keys.RightShift:
|
switch (key)
|
||||||
rightShift = state;
|
{
|
||||||
break;
|
case Keys.LeftControl:
|
||||||
case Keys.LeftAlt:
|
leftControl = state;
|
||||||
leftAlt = state;
|
break;
|
||||||
break;
|
case Keys.RightControl:
|
||||||
case Keys.RightAlt:
|
rightControl = state;
|
||||||
rightAlt = state;
|
break;
|
||||||
break;
|
case Keys.LeftShift:
|
||||||
}
|
leftShift = state;
|
||||||
|
break;
|
||||||
var e = new KeyEvent(key, GetKeyModifiers());
|
case Keys.RightShift:
|
||||||
|
rightShift = state;
|
||||||
if (hoveredWidget != null)
|
break;
|
||||||
{
|
case Keys.LeftAlt:
|
||||||
if (state == ButtonState.Pressed)
|
leftAlt = state;
|
||||||
{
|
break;
|
||||||
Bubble<IPreviewKeyDownHandler, KeyEvent>(hoveredWidget, e, x => x.OnPreviewKeyDown);
|
case Keys.RightAlt:
|
||||||
}
|
rightAlt = state;
|
||||||
else
|
break;
|
||||||
{
|
}
|
||||||
Bubble<IPreviewKeyUpHandler, KeyEvent>(hoveredWidget, e, x => x.OnPreviewKeyUp);
|
|
||||||
}
|
var e = new KeyEvent(key, GetKeyModifiers());
|
||||||
}
|
|
||||||
|
if (hoveredWidget != null)
|
||||||
if (keyboardFocus != null)
|
{
|
||||||
{
|
if (state == ButtonState.Pressed)
|
||||||
if (state == ButtonState.Pressed)
|
{
|
||||||
{
|
Bubble<IPreviewKeyDownHandler, KeyEvent>(hoveredWidget, e, x => x.OnPreviewKeyDown);
|
||||||
Bubble<IKeyDownHandler, KeyEvent>(keyboardFocus, e, x => x.OnKeyDown);
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
Bubble<IPreviewKeyUpHandler, KeyEvent>(hoveredWidget, e, x => x.OnPreviewKeyUp);
|
||||||
Bubble<IKeyUpHandler, KeyEvent>(keyboardFocus, e, x => x.OnKeyUp);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
if (keyboardFocus != null)
|
||||||
|
{
|
||||||
public void SetMouseState(MouseState state)
|
if (state == ButtonState.Pressed)
|
||||||
{
|
{
|
||||||
if (previousMouseState == null)
|
Bubble<IKeyDownHandler, KeyEvent>(keyboardFocus, e, x => x.OnKeyDown);
|
||||||
previousMouseState = state;
|
}
|
||||||
else if (previousMouseState.Value == state)
|
else
|
||||||
return;
|
{
|
||||||
|
Bubble<IKeyUpHandler, KeyEvent>(keyboardFocus, e, x => x.OnKeyUp);
|
||||||
HandleMouseEvents(previousMouseState.Value, state);
|
}
|
||||||
previousMouseState = state;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateLayout()
|
public void SetMouseState(MouseState state)
|
||||||
{
|
{
|
||||||
reachedFirstUpdate = true;
|
if (previousMouseState == null)
|
||||||
|
previousMouseState = state;
|
||||||
var mustRebuildLayout = false;
|
else if (previousMouseState.Value == state)
|
||||||
var tolerance = 0.001f;
|
return;
|
||||||
|
|
||||||
if (MathF.Abs(screenWidth - context.PhysicalScreenWidth) >= tolerance
|
HandleMouseEvents(previousMouseState.Value, state);
|
||||||
|| MathF.Abs(screenHeight - context.PhysicalScreenHeight) >= tolerance)
|
previousMouseState = state;
|
||||||
{
|
}
|
||||||
screenWidth = context.PhysicalScreenWidth;
|
|
||||||
screenHeight = context.PhysicalScreenHeight;
|
public void UpdateLayout()
|
||||||
|
{
|
||||||
mustRebuildLayout = true;
|
reachedFirstUpdate = true;
|
||||||
}
|
|
||||||
|
var mustRebuildLayout = false;
|
||||||
if (mustRebuildLayout)
|
var tolerance = 0.001f;
|
||||||
{
|
|
||||||
foreach (Widget topLevel in topLevels)
|
if (MathF.Abs(screenWidth - context.CanvasWidth) >= tolerance
|
||||||
{
|
|| MathF.Abs(screenHeight - context.CanvasHeight) >= tolerance)
|
||||||
topLevel.InvalidateLayout();
|
{
|
||||||
}
|
screenWidth = context.CanvasWidth;
|
||||||
}
|
screenHeight = context.CanvasHeight;
|
||||||
}
|
|
||||||
|
mustRebuildLayout = true;
|
||||||
public void Update(float deltaTime)
|
}
|
||||||
{
|
|
||||||
Animator.Update(deltaTime);
|
if (mustRebuildLayout)
|
||||||
|
{
|
||||||
foreach (Widget widget in this.CollapseChildren())
|
foreach (Widget topLevel in topLevels)
|
||||||
{
|
{
|
||||||
if (widget is IUpdateHandler handler)
|
topLevel.InvalidateLayout();
|
||||||
handler.Update(deltaTime);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IVisualStyle GetVisualStyle()
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (fallbackVisualStyle.FallbackFont == null)
|
foreach (Widget widget in CollapseChildren())
|
||||||
fallbackVisualStyle.FallbackFont = context.GetFallbackFont();
|
{
|
||||||
|
if (widget is IUpdateHandler handler)
|
||||||
return visualStyleOverride ?? fallbackVisualStyle;
|
handler.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void Render()
|
|
||||||
{
|
public IVisualStyle GetVisualStyle()
|
||||||
isRendering = true;
|
{
|
||||||
|
if (fallbackVisualStyle.FallbackFont == null)
|
||||||
//renderer.SetLayer(-32768);
|
fallbackVisualStyle.FallbackFont = context.GetFallbackFont();
|
||||||
|
|
||||||
foreach (Widget widget in topLevels)
|
return visualStyleOverride ?? fallbackVisualStyle;
|
||||||
widget.RenderInternal(renderer, Matrix.Identity);
|
}
|
||||||
|
|
||||||
isRendering = false;
|
public void Render()
|
||||||
}
|
{
|
||||||
|
isRendering = true;
|
||||||
internal void SubmitForLayoutUpdateInternal(Widget widget)
|
|
||||||
{
|
renderer.SetLayer(-32768);
|
||||||
if (!reachedFirstUpdate)
|
|
||||||
return;
|
foreach (Widget widget in topLevels)
|
||||||
|
widget.RenderInternal(renderer);
|
||||||
if (widget.Parent != null)
|
|
||||||
{
|
renderer.RenderBatches();
|
||||||
widget.UpdateLayout(context, widget.ContentArea);
|
|
||||||
}
|
isRendering = false;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
widget.UpdateLayout(context, new LayoutRect(0, 0, screenWidth, screenHeight));
|
internal void SubmitForLayoutUpdateInternal(Widget widget)
|
||||||
}
|
{
|
||||||
}
|
if (!reachedFirstUpdate)
|
||||||
|
return;
|
||||||
public IFontFamily GetFont(PresetFontFamily family)
|
|
||||||
{
|
if (widget.Parent != null)
|
||||||
return GetVisualStyle().GetFont(family);
|
{
|
||||||
}
|
widget.UpdateLayout(context, widget.ContentArea);
|
||||||
|
}
|
||||||
internal GraphicsDevice GetGraphicsDeviceInternal()
|
else
|
||||||
{
|
{
|
||||||
return context.GraphicsDevice;
|
widget.UpdateLayout(context, new LayoutRect(0, 0, screenWidth, screenHeight));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private IEnumerable<Widget> CollapseChildren()
|
|
||||||
{
|
public IFontFamily GetFont(PresetFontFamily family)
|
||||||
for (var i = topLevels.Count - 1; i >= 0; i--)
|
{
|
||||||
{
|
return GetVisualStyle().GetFont(family);
|
||||||
Widget toplevel = topLevels[i];
|
}
|
||||||
if (!toplevel.Enabled)
|
|
||||||
continue;
|
internal GraphicsDevice GetGraphicsDeviceInternal()
|
||||||
|
{
|
||||||
foreach (Widget child in toplevel.CollapseChildren(true, false))
|
return context.GraphicsDevice;
|
||||||
{
|
}
|
||||||
yield return child;
|
|
||||||
}
|
private IEnumerable<Widget> CollapseChildren()
|
||||||
|
{
|
||||||
yield return toplevel;
|
for (var i = topLevels.Count - 1; i >= 0; i--)
|
||||||
}
|
{
|
||||||
}
|
Widget toplevel = topLevels[i];
|
||||||
|
if (!toplevel.Enabled)
|
||||||
private Point TranslateMousePosition(Point mousePosition)
|
continue;
|
||||||
{
|
|
||||||
return new Vector2(
|
foreach (Widget child in toplevel.CollapseChildren(true, false))
|
||||||
((float)mousePosition.X / context.GraphicsDevice.PresentationParameters.BackBufferWidth) *
|
{
|
||||||
context.PhysicalScreenWidth,
|
yield return child;
|
||||||
((float)mousePosition.Y / context.GraphicsDevice.PresentationParameters.BackBufferHeight) *
|
}
|
||||||
context.PhysicalScreenHeight
|
|
||||||
).ToPoint();
|
yield return toplevel;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void HandleMouseEvents(MouseState previous, MouseState current)
|
|
||||||
{
|
private Point TranslateMousePosition(Point mousePosition)
|
||||||
var prevPosition = TranslateMousePosition(previous.Position);
|
{
|
||||||
var currPosition = TranslateMousePosition(current.Position);
|
return new Vector2(
|
||||||
|
((float)mousePosition.X / context.GraphicsDevice.PresentationParameters.BackBufferWidth) *
|
||||||
var prevWheel = previous.ScrollWheelValue;
|
context.CanvasWidth,
|
||||||
var currWheel = current.ScrollWheelValue;
|
((float)mousePosition.Y / context.GraphicsDevice.PresentationParameters.BackBufferHeight) *
|
||||||
|
context.CanvasHeight
|
||||||
var positionDelta = currPosition - prevPosition;
|
).ToPoint();
|
||||||
var wheelDelta = -(currWheel - prevWheel);
|
}
|
||||||
|
|
||||||
HandleMouseMovement(new MouseMoveEvent(currPosition, positionDelta));
|
private void HandleMouseEvents(MouseState previous, MouseState current)
|
||||||
HandleMouseScroll(new MouseScrollEvent(currPosition, wheelDelta));
|
{
|
||||||
|
var prevPosition = TranslateMousePosition(previous.Position);
|
||||||
HandleDragEvents(MouseButton.Left, previous.LeftButton, current.LeftButton, currPosition, positionDelta);
|
var currPosition = TranslateMousePosition(current.Position);
|
||||||
HandleDragEvents(MouseButton.Middle, previous.MiddleButton, current.MiddleButton, currPosition, positionDelta);
|
|
||||||
HandleDragEvents(MouseButton.Right, previous.RightButton, current.RightButton, currPosition, positionDelta);
|
var prevWheel = previous.ScrollWheelValue;
|
||||||
HandleDragEvents(MouseButton.X1, previous.XButton1, current.XButton1, currPosition, positionDelta);
|
var currWheel = current.ScrollWheelValue;
|
||||||
HandleDragEvents(MouseButton.X2, previous.XButton2, current.XButton2, currPosition, positionDelta);
|
|
||||||
}
|
var positionDelta = currPosition - prevPosition;
|
||||||
|
var wheelDelta = -(currWheel - prevWheel);
|
||||||
private void HandleDragEvents(
|
|
||||||
MouseButton button,
|
HandleMouseMovement(new MouseMoveEvent(currPosition, positionDelta));
|
||||||
ButtonState previousState,
|
HandleMouseScroll(new MouseScrollEvent(currPosition, wheelDelta));
|
||||||
ButtonState currentState,
|
|
||||||
Point position,
|
HandleDragEvents(MouseButton.Left, previous.LeftButton, current.LeftButton, currPosition, positionDelta);
|
||||||
Point movement
|
HandleDragEvents(MouseButton.Middle, previous.MiddleButton, current.MiddleButton, currPosition, positionDelta);
|
||||||
)
|
HandleDragEvents(MouseButton.Right, previous.RightButton, current.RightButton, currPosition, positionDelta);
|
||||||
{
|
HandleDragEvents(MouseButton.X1, previous.XButton1, current.XButton1, currPosition, positionDelta);
|
||||||
if (previousState != currentState)
|
HandleDragEvents(MouseButton.X2, previous.XButton2, current.XButton2, currPosition, positionDelta);
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (currentState == ButtonState.Released)
|
private void HandleDragEvents(
|
||||||
return;
|
MouseButton button,
|
||||||
|
ButtonState previousState,
|
||||||
if (widgetBeingDragged == null)
|
ButtonState currentState,
|
||||||
return;
|
Point position,
|
||||||
|
Point movement
|
||||||
var e = new MouseButtonEvent(position, movement, button, currentState);
|
)
|
||||||
Bubble<IDragHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDrag);
|
{
|
||||||
}
|
if (previousState != currentState)
|
||||||
|
return;
|
||||||
private void HandleMouseButton(MouseButton button, ButtonState previous, ButtonState current, Point position, Point delta)
|
|
||||||
{
|
if (currentState == ButtonState.Released)
|
||||||
var e = new MouseButtonEvent(position, delta, button, current);
|
return;
|
||||||
|
|
||||||
if (previous == ButtonState.Released)
|
if (widgetBeingDragged == null)
|
||||||
{
|
return;
|
||||||
if (hoveredWidget == null)
|
|
||||||
return;
|
var e = new MouseButtonEvent(position, movement, button, currentState);
|
||||||
|
Bubble<IDragHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDrag);
|
||||||
Bubble<IMouseDownHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseDown);
|
}
|
||||||
|
|
||||||
if (e.Handled)
|
private void HandleMouseButton(MouseButton button, ButtonState previous, ButtonState current, Point position, Point delta)
|
||||||
e.Unhandle();
|
{
|
||||||
|
var e = new MouseButtonEvent(position, delta, button, current);
|
||||||
widgetBeingDragged = hoveredWidget;
|
|
||||||
Bubble<IDragStartHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnDragStart);
|
if (previous == ButtonState.Released)
|
||||||
}
|
{
|
||||||
else if (previous == ButtonState.Pressed)
|
if (hoveredWidget == null)
|
||||||
{
|
return;
|
||||||
if (widgetBeingDragged != null)
|
|
||||||
{
|
Bubble<IMouseDownHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseDown);
|
||||||
Bubble<IDragEndHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDragEnd);
|
|
||||||
widgetBeingDragged = null;
|
if (e.Handled)
|
||||||
}
|
e.Unhandle();
|
||||||
|
|
||||||
if (hoveredWidget != null)
|
widgetBeingDragged = hoveredWidget;
|
||||||
{
|
Bubble<IDragStartHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnDragStart);
|
||||||
Bubble<IMouseClickHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseClick);
|
}
|
||||||
Bubble<IMouseUpHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseUp);
|
else if (previous == ButtonState.Pressed)
|
||||||
}
|
{
|
||||||
|
if (widgetBeingDragged != null)
|
||||||
if (!e.FocusWanted && hoveredWidget?.IsFocused == false)
|
{
|
||||||
SetFocusedWidget(null);
|
Bubble<IDragEndHandler, MouseButtonEvent>(widgetBeingDragged, e, x => x.OnDragEnd);
|
||||||
|
widgetBeingDragged = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (hoveredWidget != null)
|
||||||
private void Bubble<THandler, TEvent>(Widget widget, TEvent e, Func<THandler, Action<TEvent>> getHandler)
|
{
|
||||||
where TEvent : GuiEvent
|
Bubble<IMouseClickHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseClick);
|
||||||
{
|
Bubble<IMouseUpHandler, MouseButtonEvent>(hoveredWidget, e, x => x.OnMouseUp);
|
||||||
Widget? next = widget;
|
}
|
||||||
|
|
||||||
while (next != null && !e.Handled)
|
if (!e.FocusWanted && hoveredWidget?.IsFocused == false)
|
||||||
{
|
SetFocusedWidget(null);
|
||||||
if (next is THandler handler)
|
|
||||||
{
|
}
|
||||||
getHandler(handler)(e);
|
}
|
||||||
}
|
|
||||||
|
private void Bubble<THandler, TEvent>(Widget widget, TEvent e, Func<THandler, Action<TEvent>> getHandler)
|
||||||
if (e.FocusWanted)
|
where TEvent : GuiEvent
|
||||||
{
|
{
|
||||||
SetFocusedWidget(next);
|
Widget? next = widget;
|
||||||
break;
|
|
||||||
}
|
while (next != null && !e.Handled)
|
||||||
|
{
|
||||||
next = next.Parent;
|
if (next is THandler handler)
|
||||||
}
|
{
|
||||||
}
|
getHandler(handler)(e);
|
||||||
|
}
|
||||||
private void HandleMouseMovement(MouseMoveEvent e)
|
|
||||||
{
|
if (e.FocusWanted)
|
||||||
Widget? newHoveredWidget = null;
|
{
|
||||||
|
SetFocusedWidget(next);
|
||||||
foreach (Widget widget in CollapseChildren())
|
break;
|
||||||
{
|
}
|
||||||
if (!widget.IsVisible)
|
|
||||||
continue;
|
next = next.Parent;
|
||||||
|
}
|
||||||
if (widget is not IMouseHandler)
|
}
|
||||||
continue;
|
|
||||||
|
private void HandleMouseMovement(MouseMoveEvent e)
|
||||||
if (widget.ClippedContentArea.Contains(e.Position))
|
{
|
||||||
{
|
Widget? newHoveredWidget = null;
|
||||||
newHoveredWidget = widget;
|
|
||||||
break;
|
foreach (Widget widget in CollapseChildren())
|
||||||
}
|
{
|
||||||
}
|
if (!widget.IsVisible)
|
||||||
|
continue;
|
||||||
if (newHoveredWidget != hoveredWidget)
|
|
||||||
{
|
if (widget is not IMouseHandler)
|
||||||
if (hoveredWidget != null && !hoveredWidget.ContainsChild(newHoveredWidget))
|
continue;
|
||||||
{
|
|
||||||
Bubble<IMouseLeaveHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseLeave);
|
if (widget.ClippedContentArea.Contains(e.Position))
|
||||||
}
|
{
|
||||||
|
newHoveredWidget = widget;
|
||||||
hoveredWidget = newHoveredWidget;
|
break;
|
||||||
|
}
|
||||||
if (hoveredWidget != null)
|
}
|
||||||
{
|
|
||||||
Bubble<IMouseEnterHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseEnter);
|
if (newHoveredWidget != hoveredWidget)
|
||||||
}
|
{
|
||||||
}
|
if (hoveredWidget != null && !hoveredWidget.ContainsChild(newHoveredWidget))
|
||||||
|
{
|
||||||
if (hoveredWidget != null)
|
Bubble<IMouseLeaveHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseLeave);
|
||||||
{
|
}
|
||||||
Bubble<IMouseMoveHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseMove);
|
|
||||||
}
|
hoveredWidget = newHoveredWidget;
|
||||||
}
|
|
||||||
|
if (hoveredWidget != null)
|
||||||
private void HandleMouseScroll(MouseScrollEvent e)
|
{
|
||||||
{
|
Bubble<IMouseEnterHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseEnter);
|
||||||
if (e.ScrollDelta == 0)
|
}
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (hoveredWidget == null)
|
if (hoveredWidget != null)
|
||||||
return;
|
{
|
||||||
|
Bubble<IMouseMoveHandler, MouseMoveEvent>(hoveredWidget, e, x => x.OnMouseMove);
|
||||||
Bubble<IMouseScrollHandler, MouseScrollEvent>(hoveredWidget, e, x => x.OnMouseScroll);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleMouseScroll(MouseScrollEvent e)
|
||||||
|
{
|
||||||
|
if (e.ScrollDelta == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hoveredWidget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Bubble<IMouseScrollHandler, MouseScrollEvent>(hoveredWidget, e, x => x.OnMouseScroll);
|
||||||
|
}
|
||||||
}
|
}
|
0
src/AcidicGUI/GuiSynchronizationContext.cs
Normal file → Executable file
0
src/AcidicGUI/GuiSynchronizationContext.cs
Normal file → Executable file
62
src/AcidicGUI/IGuiContext.cs
Normal file → Executable file
62
src/AcidicGUI/IGuiContext.cs
Normal file → Executable file
|
@ -1,36 +1,28 @@
|
||||||
using AcidicGUI.Effects;
|
using AcidicGUI.Effects;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using AcidicGUI.TextRendering;
|
using AcidicGUI.TextRendering;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
|
namespace AcidicGUI;
|
||||||
namespace AcidicGUI;
|
|
||||||
|
public interface IGuiContext
|
||||||
public interface IGuiContext
|
{
|
||||||
{
|
int PhysicalWidth { get; }
|
||||||
int PhysicalScreenWidth { get; }
|
int PhysicalHeight { get; }
|
||||||
int PhysicalScreenHeight { get; }
|
int CanvasWidth { get; }
|
||||||
GraphicsDevice GraphicsDevice { get; }
|
int CanvasHeight { get; }
|
||||||
|
GraphicsDevice GraphicsDevice { get; }
|
||||||
void Render(
|
|
||||||
VertexBuffer vertices,
|
void Render(VertexPositionColorTexture[] vertices, int[] indices, Texture2D? texture, LayoutRect? clipRect = null);
|
||||||
IndexBuffer indices,
|
void Render(VertexBuffer vertices, IndexBuffer indices, int offset, int primitiveCount, Texture2D? texture, LayoutRect? clipRect = null, IEffect? effectOverride = null, float opacity = 1);
|
||||||
int offset,
|
|
||||||
int primitiveCount,
|
/// <summary>
|
||||||
Texture2D? texture,
|
/// Renders the user interface to the given RenderTarget2D. Useful for certain widget rendering techniques such as background blurs.
|
||||||
LayoutRect? clipRect = null,
|
/// </summary>
|
||||||
IEffect? effectOverride = null,
|
/// <param name="destination"></param>
|
||||||
float opacity = 1,
|
void Grab(RenderTarget2D destination);
|
||||||
Matrix? widgetTransform = null
|
|
||||||
);
|
void RestoreRenderState();
|
||||||
|
|
||||||
/// <summary>
|
IFontFamily GetFallbackFont();
|
||||||
/// Renders the user interface to the given RenderTarget2D. Useful for certain widget rendering techniques such as background blurs.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destination"></param>
|
|
||||||
void Grab(RenderTarget2D destination);
|
|
||||||
|
|
||||||
void RestoreRenderState();
|
|
||||||
|
|
||||||
IFontFamily GetFallbackFont();
|
|
||||||
}
|
}
|
0
src/AcidicGUI/IOrderedCollection.cs
Normal file → Executable file
0
src/AcidicGUI/IOrderedCollection.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/Direction.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/Direction.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/FlexMode.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/FlexMode.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/HorizontalAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/HorizontalAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/LayoutRect.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/LayoutRect.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/Padding.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/Padding.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/TextAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/TextAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/VerticalAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/Layout/VerticalAlignment.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/DataHelper.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/DataHelper.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/INotifyDataChanged.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/INotifyDataChanged.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/ListAdapter.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/ListAdapter.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/RecyclableWidgetController.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/RecyclableWidgetController.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/RecycleBin.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/RecycleBin.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/ViewHolder.cs
Normal file → Executable file
0
src/AcidicGUI/ListAdapters/ViewHolder.cs
Normal file → Executable file
729
src/AcidicGUI/Rendering/GeometryHelper.cs
Normal file → Executable file
729
src/AcidicGUI/Rendering/GeometryHelper.cs
Normal file → Executable file
|
@ -1,363 +1,368 @@
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using FontStashSharp.Interfaces;
|
using FontStashSharp.Interfaces;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
namespace AcidicGUI.Rendering;
|
namespace AcidicGUI.Rendering;
|
||||||
|
|
||||||
public class GeometryHelper : IFontStashRenderer2
|
public class GeometryHelper : IFontStashRenderer2
|
||||||
{
|
{
|
||||||
private readonly GuiMeshBuilder whiteMesh;
|
private readonly GuiMeshBuilder whiteMesh;
|
||||||
private readonly Dictionary<Texture2D, GuiMeshBuilder> meshes = new();
|
private readonly Dictionary<Texture2D, GuiMeshBuilder> meshes = new();
|
||||||
private readonly GuiRenderer guiRenderer;
|
private readonly GuiRenderer guiRenderer;
|
||||||
private readonly bool desaturate;
|
private readonly bool desaturate;
|
||||||
private readonly LayoutRect? clipRect;
|
private readonly LayoutRect? clipRect;
|
||||||
private readonly List<GuiSubMesh> flushedMeshes = new();
|
private readonly List<GuiSubMesh> flushedMeshes = new();
|
||||||
|
|
||||||
public float Layer => guiRenderer.Layer;
|
public float Layer => guiRenderer.Layer;
|
||||||
|
|
||||||
public GeometryHelper(GuiRenderer guiRenderer, bool desaturate, LayoutRect? clipRect)
|
public GeometryHelper(GuiRenderer guiRenderer, bool desaturate, LayoutRect? clipRect)
|
||||||
{
|
{
|
||||||
this.desaturate = desaturate;
|
this.desaturate = desaturate;
|
||||||
this.guiRenderer = guiRenderer;
|
this.guiRenderer = guiRenderer;
|
||||||
this.clipRect = clipRect;
|
this.clipRect = clipRect;
|
||||||
|
|
||||||
whiteMesh = new GuiMeshBuilder(this, null, desaturate);
|
whiteMesh = new GuiMeshBuilder(this, null, desaturate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Flush()
|
public void PushLayer()
|
||||||
{
|
{
|
||||||
flushedMeshes.Add(whiteMesh.ExportSubMesh());
|
guiRenderer.PushLayer();
|
||||||
whiteMesh.Clear();
|
}
|
||||||
|
|
||||||
foreach (GuiMeshBuilder mesh in meshes.Values)
|
private void Flush()
|
||||||
{
|
{
|
||||||
flushedMeshes.Add(mesh.ExportSubMesh());
|
flushedMeshes.Add(whiteMesh.ExportSubMesh());
|
||||||
mesh.Clear();
|
whiteMesh.Clear();
|
||||||
}
|
|
||||||
}
|
foreach (GuiMeshBuilder mesh in meshes.Values)
|
||||||
|
{
|
||||||
public GuiMesh ExportMesh()
|
flushedMeshes.Add(mesh.ExportSubMesh());
|
||||||
{
|
mesh.Clear();
|
||||||
Flush();
|
}
|
||||||
|
}
|
||||||
var meshList = flushedMeshes.ToArray();
|
|
||||||
|
public GuiMesh ExportMesh()
|
||||||
return new GuiMesh(meshList, clipRect);
|
{
|
||||||
}
|
Flush();
|
||||||
|
|
||||||
public GuiMeshBuilder GetMeshBuilder(Texture2D? texture)
|
var meshList = flushedMeshes.ToArray();
|
||||||
{
|
|
||||||
if (texture == null)
|
return new GuiMesh(meshList, clipRect);
|
||||||
return whiteMesh;
|
}
|
||||||
|
|
||||||
if (!meshes.TryGetValue(texture, out GuiMeshBuilder? builder))
|
public GuiMeshBuilder GetMeshBuilder(Texture2D? texture)
|
||||||
{
|
{
|
||||||
builder = new GuiMeshBuilder(this, texture, desaturate);
|
if (texture == null)
|
||||||
meshes.Add(texture, builder);
|
return whiteMesh;
|
||||||
}
|
|
||||||
|
if (!meshes.TryGetValue(texture, out GuiMeshBuilder? builder))
|
||||||
return meshes[texture];
|
{
|
||||||
}
|
builder = new GuiMeshBuilder(this, texture, desaturate);
|
||||||
|
meshes.Add(texture, builder);
|
||||||
public void AddRoundedRectangle(LayoutRect rectangle, float uniformRadius, Color color, Texture2D? texture = null)
|
}
|
||||||
{
|
|
||||||
AddRoundedRectangle(rectangle, uniformRadius, uniformRadius, uniformRadius, uniformRadius, color, texture);
|
return meshes[texture];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddQuadOutline(
|
public void AddRoundedRectangle(LayoutRect rectangle, float uniformRadius, Color color, Texture2D? texture = null)
|
||||||
LayoutRect rectangle,
|
{
|
||||||
float thickness,
|
AddRoundedRectangle(rectangle, uniformRadius, uniformRadius, uniformRadius, uniformRadius, color, texture);
|
||||||
Color color,
|
}
|
||||||
Texture2D? texture = null
|
|
||||||
)
|
public void AddQuadOutline(
|
||||||
{
|
LayoutRect rectangle,
|
||||||
float smallerHalf = Math.Min(rectangle.Width, rectangle.Height) / 2f;
|
float thickness,
|
||||||
if (smallerHalf <= thickness)
|
Color color,
|
||||||
{
|
Texture2D? texture = null
|
||||||
AddQuad(rectangle, color, texture);
|
)
|
||||||
return;
|
{
|
||||||
}
|
float smallerHalf = Math.Min(rectangle.Width, rectangle.Height) / 2f;
|
||||||
|
if (smallerHalf <= thickness)
|
||||||
float texelWidth = 1f / (texture?.Width ?? 1f);
|
{
|
||||||
float texelHeight = 1f / (texture?.Height ?? 1f);
|
AddQuad(rectangle, color, texture);
|
||||||
|
return;
|
||||||
var mesh = GetMeshBuilder(texture);
|
}
|
||||||
|
|
||||||
var tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color, new Vector2(0, 0));
|
float texelWidth = 1f / (texture?.Width ?? 1f);
|
||||||
var tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color, new Vector2(1, 0));
|
float texelHeight = 1f / (texture?.Height ?? 1f);
|
||||||
var bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color, new Vector2(0, 1));
|
|
||||||
var br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color, new Vector2(1, 1));
|
var mesh = GetMeshBuilder(texture);
|
||||||
var tlInner = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + thickness), color, new Vector2(texelWidth * thickness, texelHeight * thickness));
|
|
||||||
var trInner = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + thickness), color, new Vector2(1 - texelWidth * thickness, texelHeight * thickness));
|
var tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color, new Vector2(0, 0));
|
||||||
var blInner = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - thickness), color, new Vector2(texelWidth * thickness, 1 - texelHeight * thickness));
|
var tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color, new Vector2(1, 0));
|
||||||
var brInner = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - thickness), color, new Vector2(1 - texelWidth * thickness, 1 - texelHeight * thickness));
|
var bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color, new Vector2(0, 1));
|
||||||
|
var br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color, new Vector2(1, 1));
|
||||||
mesh.AddQuad(tl, tr, tlInner, trInner);
|
var tlInner = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + thickness), color, new Vector2(texelWidth * thickness, texelHeight * thickness));
|
||||||
mesh.AddQuad(tl, tlInner, bl, blInner);
|
var trInner = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + thickness), color, new Vector2(1 - texelWidth * thickness, texelHeight * thickness));
|
||||||
mesh.AddQuad(trInner, tr, brInner, br);
|
var blInner = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - thickness), color, new Vector2(texelWidth * thickness, 1 - texelHeight * thickness));
|
||||||
mesh.AddQuad(blInner, brInner, bl, br);
|
var brInner = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - thickness), color, new Vector2(1 - texelWidth * thickness, 1 - texelHeight * thickness));
|
||||||
}
|
|
||||||
|
mesh.AddQuad(tl, tr, tlInner, trInner);
|
||||||
public void AddQuad(LayoutRect rectangle, Color color, Texture2D? texture = null)
|
mesh.AddQuad(tl, tlInner, bl, blInner);
|
||||||
{
|
mesh.AddQuad(trInner, tr, brInner, br);
|
||||||
if (color.A == 0)
|
mesh.AddQuad(blInner, brInner, bl, br);
|
||||||
return;
|
}
|
||||||
|
|
||||||
var mesh = GetMeshBuilder(texture);
|
public void AddQuad(LayoutRect rectangle, Color color, Texture2D? texture = null)
|
||||||
|
{
|
||||||
int tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color, new Vector2(0, 0));
|
if (color.A == 0)
|
||||||
int tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color, new Vector2(1, 0));
|
return;
|
||||||
int bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color, new Vector2(0, 1));
|
|
||||||
int br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color, new Vector2(1, 1));
|
var mesh = GetMeshBuilder(texture);
|
||||||
|
|
||||||
mesh.AddQuad(tl, tr, bl, br);
|
int tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color, new Vector2(0, 0));
|
||||||
}
|
int tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color, new Vector2(1, 0));
|
||||||
|
int bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color, new Vector2(0, 1));
|
||||||
public void AddRoundedRectangle(
|
int br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color, new Vector2(1, 1));
|
||||||
LayoutRect rectangle,
|
|
||||||
float radiusTopLeft,
|
mesh.AddQuad(tl, tr, bl, br);
|
||||||
float radiusTopRight,
|
}
|
||||||
float radiusBottomLeft,
|
|
||||||
float radiusBottomRight,
|
public void AddRoundedRectangle(
|
||||||
Color color,
|
LayoutRect rectangle,
|
||||||
Texture2D? texture = null
|
float radiusTopLeft,
|
||||||
)
|
float radiusTopRight,
|
||||||
{
|
float radiusBottomLeft,
|
||||||
var mesh = GetMeshBuilder(texture);
|
float radiusBottomRight,
|
||||||
|
Color color,
|
||||||
float halfWidth = rectangle.Width / 2f;
|
Texture2D? texture = null
|
||||||
float halfHeight = rectangle.Height / 2f;
|
)
|
||||||
|
{
|
||||||
float smallerHalf = MathF.Min(halfWidth, halfHeight);
|
var mesh = GetMeshBuilder(texture);
|
||||||
|
|
||||||
radiusTopLeft = MathHelper.Clamp(radiusTopLeft, 0, smallerHalf);
|
float halfWidth = rectangle.Width / 2f;
|
||||||
radiusBottomLeft = MathHelper.Clamp(radiusBottomLeft, 0, smallerHalf);
|
float halfHeight = rectangle.Height / 2f;
|
||||||
radiusTopRight = MathHelper.Clamp(radiusTopRight, 0, smallerHalf);
|
|
||||||
radiusBottomRight = MathHelper.Clamp(radiusBottomRight, 0, smallerHalf);
|
float smallerHalf = MathF.Min(halfWidth, halfHeight);
|
||||||
|
|
||||||
if (radiusTopLeft <= 0 && radiusTopRight <= 0 && radiusBottomLeft <= 0 && radiusBottomRight <= 0)
|
radiusTopLeft = MathHelper.Clamp(radiusTopLeft, 0, smallerHalf);
|
||||||
{
|
radiusBottomLeft = MathHelper.Clamp(radiusBottomLeft, 0, smallerHalf);
|
||||||
AddQuad(rectangle, color);
|
radiusTopRight = MathHelper.Clamp(radiusTopRight, 0, smallerHalf);
|
||||||
return;
|
radiusBottomRight = MathHelper.Clamp(radiusBottomRight, 0, smallerHalf);
|
||||||
}
|
|
||||||
|
if (radiusTopLeft <= 0 && radiusTopRight <= 0 && radiusBottomLeft <= 0 && radiusBottomRight <= 0)
|
||||||
float radiusTopLeftUv = radiusTopLeft / rectangle.Width;
|
{
|
||||||
float radiusTopRightUv = radiusTopRight / rectangle.Width;
|
AddQuad(rectangle, color);
|
||||||
float radiusBottomLeftUv = radiusBottomLeft / rectangle.Width;
|
return;
|
||||||
float radiusBottomRightUv = radiusBottomRight / rectangle.Width;
|
}
|
||||||
|
|
||||||
|
float radiusTopLeftUv = radiusTopLeft / rectangle.Width;
|
||||||
int innerTl = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + radiusTopLeft), color, new Vector2(radiusTopLeftUv, radiusTopLeftUv));
|
float radiusTopRightUv = radiusTopRight / rectangle.Width;
|
||||||
int innerTr = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + radiusTopRight), color, new Vector2(1 - radiusTopRightUv, radiusTopRightUv));
|
float radiusBottomLeftUv = radiusBottomLeft / rectangle.Width;
|
||||||
int innerBl = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - radiusBottomLeft), color, new Vector2(radiusBottomLeftUv, 1 - radiusBottomLeftUv));
|
float radiusBottomRightUv = radiusBottomRight / rectangle.Width;
|
||||||
int innerBr = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - radiusBottomRight), color, new Vector2(1 - radiusBottomRightUv, 1 - radiusBottomRightUv));
|
|
||||||
|
|
||||||
int outerTl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top + radiusTopLeft), color, new Vector2(0, radiusTopLeftUv));
|
int innerTl = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + radiusTopLeft), color, new Vector2(radiusTopLeftUv, radiusTopLeftUv));
|
||||||
int outerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top), color, new Vector2(radiusTopLeftUv, 0));
|
int innerTr = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + radiusTopRight), color, new Vector2(1 - radiusTopRightUv, radiusTopRightUv));
|
||||||
int outerTr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top + radiusTopRight), color, new Vector2(1, radiusTopRightUv));
|
int innerBl = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - radiusBottomLeft), color, new Vector2(radiusBottomLeftUv, 1 - radiusBottomLeftUv));
|
||||||
int outerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top), color, new Vector2(1 - radiusTopRightUv, 0));
|
int innerBr = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - radiusBottomRight), color, new Vector2(1 - radiusBottomRightUv, 1 - radiusBottomRightUv));
|
||||||
int outerBl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom - radiusBottomLeft), color, new Vector2(0, 1 - radiusBottomLeftUv));
|
|
||||||
int outerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom), color, new Vector2(radiusBottomLeftUv, 1));
|
int outerTl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top + radiusTopLeft), color, new Vector2(0, radiusTopLeftUv));
|
||||||
int outerBr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom - radiusBottomRight), color, new Vector2(1, 1 - radiusBottomRightUv));
|
int outerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top), color, new Vector2(radiusTopLeftUv, 0));
|
||||||
int outerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom), color, new Vector2(1 - radiusBottomRightUv, 1));
|
int outerTr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top + radiusTopRight), color, new Vector2(1, radiusTopRightUv));
|
||||||
|
int outerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top), color, new Vector2(1 - radiusTopRightUv, 0));
|
||||||
mesh.AddQuad(outerTl1, innerTl, outerBl1, innerBl);
|
int outerBl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom - radiusBottomLeft), color, new Vector2(0, 1 - radiusBottomLeftUv));
|
||||||
mesh.AddQuad(outerTl2, outerTr2, innerTl, innerTr);
|
int outerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom), color, new Vector2(radiusBottomLeftUv, 1));
|
||||||
mesh.AddQuad(innerTr, outerTr1, innerBr, outerBr1);
|
int outerBr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom - radiusBottomRight), color, new Vector2(1, 1 - radiusBottomRightUv));
|
||||||
mesh.AddQuad(innerBl, innerBr, outerBl2, outerBr2);
|
int outerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom), color, new Vector2(1 - radiusBottomRightUv, 1));
|
||||||
mesh.AddQuad(innerTl, innerTr, innerBl, innerBr);
|
|
||||||
|
mesh.AddQuad(outerTl1, innerTl, outerBl1, innerBl);
|
||||||
AddQuarterCircleAroundPivotVertices(mesh, innerTl, outerTl2, radiusTopLeft, -1, -1, true, color, radiusTopLeftUv, radiusTopLeftUv, radiusTopLeftUv);
|
mesh.AddQuad(outerTl2, outerTr2, innerTl, innerTr);
|
||||||
AddQuarterCircleAroundPivotVertices(mesh, innerTr, outerTr2, radiusTopRight, 1, -1, false, color, 1 - radiusTopRightUv, radiusTopRightUv, radiusTopRightUv);
|
mesh.AddQuad(innerTr, outerTr1, innerBr, outerBr1);
|
||||||
AddQuarterCircleAroundPivotVertices(mesh, innerBl, outerBl2, radiusBottomLeft, -1, 1, false, color, radiusBottomLeftUv, 1 - radiusBottomLeftUv, radiusBottomLeftUv);
|
mesh.AddQuad(innerBl, innerBr, outerBl2, outerBr2);
|
||||||
AddQuarterCircleAroundPivotVertices(mesh, innerBr, outerBr2, radiusBottomRight, 1, 1, true, color, 1 - radiusBottomRightUv, 1 - radiusBottomRightUv, radiusBottomRightUv);
|
mesh.AddQuad(innerTl, innerTr, innerBl, innerBr);
|
||||||
}
|
|
||||||
|
AddQuarterCircleAroundPivotVertices(mesh, innerTl, outerTl2, radiusTopLeft, -1, -1, true, color, radiusTopLeftUv, radiusTopLeftUv, radiusTopLeftUv);
|
||||||
private void AddQuarterCircleAroundPivotVertices(GuiMeshBuilder mesh, int pivotVertex, int extent, float radius, float directionH, float directionV, bool reverseWinding, Color color, float uvX, float uvY, float texelRadius)
|
AddQuarterCircleAroundPivotVertices(mesh, innerTr, outerTr2, radiusTopRight, 1, -1, false, color, 1 - radiusTopRightUv, radiusTopRightUv, radiusTopRightUv);
|
||||||
{
|
AddQuarterCircleAroundPivotVertices(mesh, innerBl, outerBl2, radiusBottomLeft, -1, 1, false, color, radiusBottomLeftUv, 1 - radiusBottomLeftUv, radiusBottomLeftUv);
|
||||||
Vector3 center = mesh[pivotVertex].Position;
|
AddQuarterCircleAroundPivotVertices(mesh, innerBr, outerBr2, radiusBottomRight, 1, 1, true, color, 1 - radiusBottomRightUv, 1 - radiusBottomRightUv, radiusBottomRightUv);
|
||||||
|
}
|
||||||
int last = extent;
|
|
||||||
|
private void AddQuarterCircleAroundPivotVertices(GuiMeshBuilder mesh, int pivotVertex, int extent, float radius, float directionH, float directionV, bool reverseWinding, Color color, float uvX, float uvY, float texelRadius)
|
||||||
const int segments = 16;
|
{
|
||||||
|
Vector3 center = mesh[pivotVertex].Position;
|
||||||
for (var i = 0; i < segments; i++)
|
|
||||||
{
|
int last = extent;
|
||||||
var t = (i / (segments - 1f)) * MathF.PI * 0.5f;
|
|
||||||
var x = MathF.Sin(t);
|
const int segments = 16;
|
||||||
var y = MathF.Cos(t);
|
|
||||||
|
for (var i = 0; i < segments; i++)
|
||||||
float x1 = x * (radius * directionH) + center.X;
|
{
|
||||||
float y1 = y * (radius * directionV) + center.Y;
|
var t = (i / (segments - 1f)) * MathF.PI * 0.5f;
|
||||||
|
var x = MathF.Sin(t);
|
||||||
float u = (x * (texelRadius * directionH)) + uvX;
|
var y = MathF.Cos(t);
|
||||||
float v = (y * (texelRadius * directionV)) + uvY;
|
|
||||||
|
float x1 = x * (radius * directionH) + center.X;
|
||||||
|
float y1 = y * (radius * directionV) + center.Y;
|
||||||
|
|
||||||
int next = mesh.AddVertex(new Vector2(x1, y1), color, new Vector2(u, v));
|
float u = (x * (texelRadius * directionH)) + uvX;
|
||||||
|
float v = (y * (texelRadius * directionV)) + uvY;
|
||||||
if (reverseWinding)
|
|
||||||
mesh.AddTriangle(pivotVertex, next, last);
|
|
||||||
else
|
|
||||||
mesh.AddTriangle(last, next, pivotVertex);
|
int next = mesh.AddVertex(new Vector2(x1, y1), color, new Vector2(u, v));
|
||||||
|
|
||||||
last = next;
|
if (reverseWinding)
|
||||||
}
|
mesh.AddTriangle(pivotVertex, next, last);
|
||||||
}
|
else
|
||||||
|
mesh.AddTriangle(last, next, pivotVertex);
|
||||||
public void AddRoundedRectangleOutline(LayoutRect rectangle, float thickness, float uniformRadius, Color color, Texture2D? texture = null)
|
|
||||||
{
|
last = next;
|
||||||
AddRoundedRectangleOutline(rectangle, thickness, uniformRadius, uniformRadius, uniformRadius, uniformRadius,
|
}
|
||||||
color, texture);
|
}
|
||||||
}
|
|
||||||
|
public void AddRoundedRectangleOutline(LayoutRect rectangle, float thickness, float uniformRadius, Color color, Texture2D? texture = null)
|
||||||
public void AddRoundedRectangleOutline(LayoutRect rectangle, float thickness, float radiusTopLeft,
|
{
|
||||||
float radiusTopRight, float radiusBottomLeft, float radiusBottomRight, Color color, Texture2D? texture = null)
|
AddRoundedRectangleOutline(rectangle, thickness, uniformRadius, uniformRadius, uniformRadius, uniformRadius,
|
||||||
{
|
color, texture);
|
||||||
if (thickness <= 0)
|
}
|
||||||
return;
|
|
||||||
|
public void AddRoundedRectangleOutline(LayoutRect rectangle, float thickness, float radiusTopLeft,
|
||||||
float halfWidth = rectangle.Width / 2f;
|
float radiusTopRight, float radiusBottomLeft, float radiusBottomRight, Color color, Texture2D? texture = null)
|
||||||
float halfHeight = rectangle.Height / 2f;
|
{
|
||||||
|
if (thickness <= 0)
|
||||||
float smallerHalf = MathF.Min(halfWidth, halfHeight);
|
return;
|
||||||
|
|
||||||
if (thickness >= smallerHalf)
|
float halfWidth = rectangle.Width / 2f;
|
||||||
{
|
float halfHeight = rectangle.Height / 2f;
|
||||||
AddRoundedRectangle(rectangle, radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight, color, texture);
|
|
||||||
return;
|
float smallerHalf = MathF.Min(halfWidth, halfHeight);
|
||||||
}
|
|
||||||
|
if (thickness >= smallerHalf)
|
||||||
radiusTopLeft = MathHelper.Clamp(radiusTopLeft, 0, smallerHalf);
|
{
|
||||||
radiusBottomLeft = MathHelper.Clamp(radiusBottomLeft, 0, smallerHalf);
|
AddRoundedRectangle(rectangle, radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight, color, texture);
|
||||||
radiusTopRight = MathHelper.Clamp(radiusTopRight, 0, smallerHalf);
|
return;
|
||||||
radiusBottomRight = MathHelper.Clamp(radiusBottomRight, 0, smallerHalf);
|
}
|
||||||
|
|
||||||
|
radiusTopLeft = MathHelper.Clamp(radiusTopLeft, 0, smallerHalf);
|
||||||
if (radiusTopLeft <= 0 && radiusTopRight <= 0 && radiusBottomLeft <= 0 && radiusBottomRight <= 0)
|
radiusBottomLeft = MathHelper.Clamp(radiusBottomLeft, 0, smallerHalf);
|
||||||
return;
|
radiusTopRight = MathHelper.Clamp(radiusTopRight, 0, smallerHalf);
|
||||||
|
radiusBottomRight = MathHelper.Clamp(radiusBottomRight, 0, smallerHalf);
|
||||||
var mesh = GetMeshBuilder(texture);
|
|
||||||
|
|
||||||
int innerTl = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + thickness), color);
|
if (radiusTopLeft <= 0 && radiusTopRight <= 0 && radiusBottomLeft <= 0 && radiusBottomRight <= 0)
|
||||||
int innerTr = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + thickness), color);
|
return;
|
||||||
int innerBl = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - thickness), color);
|
|
||||||
int innerBr = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - thickness), color);
|
var mesh = GetMeshBuilder(texture);
|
||||||
int innerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + thickness), color);
|
|
||||||
int innerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + thickness), color);
|
int innerTl = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + thickness), color);
|
||||||
int innerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - thickness), color);
|
int innerTr = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + thickness), color);
|
||||||
int innerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - thickness), color);
|
int innerBl = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - thickness), color);
|
||||||
int innerTl3 = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + radiusTopLeft), color);
|
int innerBr = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - thickness), color);
|
||||||
int innerTr3 = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + radiusTopRight), color);
|
int innerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + thickness), color);
|
||||||
int innerBl3 = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - radiusBottomLeft), color);
|
int innerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + thickness), color);
|
||||||
int innerBr3 = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - radiusBottomRight), color);
|
int innerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - thickness), color);
|
||||||
|
int innerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - thickness), color);
|
||||||
int outerTl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top + radiusTopLeft), color);
|
int innerTl3 = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Top + radiusTopLeft), color);
|
||||||
int outerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top), color);
|
int innerTr3 = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Top + radiusTopRight), color);
|
||||||
int outerTr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top + radiusTopRight), color);
|
int innerBl3 = mesh.AddVertex(new Vector2(rectangle.Left + thickness, rectangle.Bottom - radiusBottomLeft), color);
|
||||||
int outerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top), color);
|
int innerBr3 = mesh.AddVertex(new Vector2(rectangle.Right - thickness, rectangle.Bottom - radiusBottomRight), color);
|
||||||
int outerBl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom - radiusBottomLeft), color);
|
|
||||||
int outerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom), color);
|
int outerTl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top + radiusTopLeft), color);
|
||||||
int outerBr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom - radiusBottomRight), color);
|
int outerTl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top), color);
|
||||||
int outerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom), color);
|
int outerTr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top + radiusTopRight), color);
|
||||||
|
int outerTr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusTopRight, rectangle.Top), color);
|
||||||
Vector2 cTl = new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + radiusTopLeft);
|
int outerBl1 = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom - radiusBottomLeft), color);
|
||||||
Vector2 cTr = new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + radiusTopRight);
|
int outerBl2 = mesh.AddVertex(new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom), color);
|
||||||
Vector2 cBl = new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - radiusBottomLeft);
|
int outerBr1 = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom - radiusBottomRight), color);
|
||||||
Vector2 cBr = new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - radiusBottomRight);
|
int outerBr2 = mesh.AddVertex(new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom), color);
|
||||||
|
|
||||||
mesh.AddQuad(outerTl1, innerTl3, outerBl1, innerBl3);
|
Vector2 cTl = new Vector2(rectangle.Left + radiusTopLeft, rectangle.Top + radiusTopLeft);
|
||||||
mesh.AddQuad(outerTl2, outerTr2, innerTl2, innerTr2);
|
Vector2 cTr = new Vector2(rectangle.Right - radiusTopRight, rectangle.Top + radiusTopRight);
|
||||||
mesh.AddQuad(innerTr3, outerTr1, innerBr3, outerBr1);
|
Vector2 cBl = new Vector2(rectangle.Left + radiusBottomLeft, rectangle.Bottom - radiusBottomLeft);
|
||||||
mesh.AddQuad(innerBl2, innerBr2, outerBl2, outerBr2);
|
Vector2 cBr = new Vector2(rectangle.Right - radiusBottomRight, rectangle.Bottom - radiusBottomRight);
|
||||||
|
|
||||||
AddRoundedRectangleOutlineCurve(mesh, cTl, innerTl, thickness, radiusTopLeft, -1, -1, true, color);
|
mesh.AddQuad(outerTl1, innerTl3, outerBl1, innerBl3);
|
||||||
AddRoundedRectangleOutlineCurve(mesh, cTr, innerTr, thickness, radiusTopRight, 1, -1, false, color);
|
mesh.AddQuad(outerTl2, outerTr2, innerTl2, innerTr2);
|
||||||
AddRoundedRectangleOutlineCurve(mesh, cBl, innerBl, thickness, radiusBottomLeft, -1, 1, false, color);
|
mesh.AddQuad(innerTr3, outerTr1, innerBr3, outerBr1);
|
||||||
AddRoundedRectangleOutlineCurve(mesh, cBr, innerBr, thickness, radiusBottomRight, 1, 1, true, color);
|
mesh.AddQuad(innerBl2, innerBr2, outerBl2, outerBr2);
|
||||||
}
|
|
||||||
|
AddRoundedRectangleOutlineCurve(mesh, cTl, innerTl, thickness, radiusTopLeft, -1, -1, true, color);
|
||||||
private void AddRoundedRectangleOutlineCurve(GuiMeshBuilder mesh, Vector2 center, int innerCorner, float thickness, float radius, float directionH, float directionV, bool reverseWinding, Color color)
|
AddRoundedRectangleOutlineCurve(mesh, cTr, innerTr, thickness, radiusTopRight, 1, -1, false, color);
|
||||||
{
|
AddRoundedRectangleOutlineCurve(mesh, cBl, innerBl, thickness, radiusBottomLeft, -1, 1, false, color);
|
||||||
const int segments = 16;
|
AddRoundedRectangleOutlineCurve(mesh, cBr, innerBr, thickness, radiusBottomRight, 1, 1, true, color);
|
||||||
|
}
|
||||||
var connectToInnerCorner = false;
|
|
||||||
if (radius < thickness)
|
private void AddRoundedRectangleOutlineCurve(GuiMeshBuilder mesh, Vector2 center, int innerCorner, float thickness, float radius, float directionH, float directionV, bool reverseWinding, Color color)
|
||||||
{
|
{
|
||||||
connectToInnerCorner = true;
|
const int segments = 16;
|
||||||
thickness = radius;
|
|
||||||
}
|
var connectToInnerCorner = false;
|
||||||
|
if (radius < thickness)
|
||||||
int currentInner = 0;
|
{
|
||||||
int currentOuter = 0;
|
connectToInnerCorner = true;
|
||||||
|
thickness = radius;
|
||||||
for (var i = 0; i < segments; i++)
|
}
|
||||||
{
|
|
||||||
var t = (i / (segments - 1f)) * MathF.PI * 0.5f;
|
int currentInner = 0;
|
||||||
var x = MathF.Sin(t);
|
int currentOuter = 0;
|
||||||
var y = MathF.Cos(t);
|
|
||||||
|
for (var i = 0; i < segments; i++)
|
||||||
var xOuter = x * (radius * directionH) + center.X;
|
{
|
||||||
var yOuter = y * (radius * directionV) + center.Y;
|
var t = (i / (segments - 1f)) * MathF.PI * 0.5f;
|
||||||
var xInner = x * ((radius * directionH) + (thickness * -directionH)) + center.X;
|
var x = MathF.Sin(t);
|
||||||
var yInner = y * ((radius * directionV) + (thickness * -directionV)) + center.Y;
|
var y = MathF.Cos(t);
|
||||||
|
|
||||||
int nextInner = mesh.AddVertex(new Vector2(xInner, yInner), color);
|
var xOuter = x * (radius * directionH) + center.X;
|
||||||
int nextOuter = mesh.AddVertex(new Vector2(xOuter, yOuter), color);
|
var yOuter = y * (radius * directionV) + center.Y;
|
||||||
|
var xInner = x * ((radius * directionH) + (thickness * -directionH)) + center.X;
|
||||||
if (reverseWinding)
|
var yInner = y * ((radius * directionV) + (thickness * -directionV)) + center.Y;
|
||||||
{
|
|
||||||
if (i > 0)
|
int nextInner = mesh.AddVertex(new Vector2(xInner, yInner), color);
|
||||||
{
|
int nextOuter = mesh.AddVertex(new Vector2(xOuter, yOuter), color);
|
||||||
mesh.AddTriangle(nextInner, currentOuter, currentInner);
|
|
||||||
mesh.AddTriangle(nextOuter, currentOuter, nextInner);
|
if (reverseWinding)
|
||||||
}
|
{
|
||||||
|
if (i > 0)
|
||||||
if (connectToInnerCorner)
|
{
|
||||||
{
|
mesh.AddTriangle(nextInner, currentOuter, currentInner);
|
||||||
if (i == 0 || i == segments - 1)
|
mesh.AddTriangle(nextOuter, currentOuter, nextInner);
|
||||||
{
|
}
|
||||||
mesh.AddTriangle(innerCorner, nextInner, nextOuter);
|
|
||||||
}
|
if (connectToInnerCorner)
|
||||||
}
|
{
|
||||||
}
|
if (i == 0 || i == segments - 1)
|
||||||
else
|
{
|
||||||
{
|
mesh.AddTriangle(innerCorner, nextInner, nextOuter);
|
||||||
if (i > 0)
|
}
|
||||||
{
|
}
|
||||||
mesh.AddTriangle(currentInner, currentOuter, nextInner);
|
}
|
||||||
mesh.AddTriangle(nextInner, currentOuter, nextOuter);
|
else
|
||||||
}
|
{
|
||||||
|
if (i > 0)
|
||||||
if (connectToInnerCorner)
|
{
|
||||||
{
|
mesh.AddTriangle(currentInner, currentOuter, nextInner);
|
||||||
if (i == 0 || i == segments - 1)
|
mesh.AddTriangle(nextInner, currentOuter, nextOuter);
|
||||||
{
|
}
|
||||||
mesh.AddTriangle(nextOuter, nextInner, innerCorner);
|
|
||||||
}
|
if (connectToInnerCorner)
|
||||||
}
|
{
|
||||||
}
|
if (i == 0 || i == segments - 1)
|
||||||
|
{
|
||||||
currentInner = nextInner;
|
mesh.AddTriangle(nextOuter, nextInner, innerCorner);
|
||||||
currentOuter = nextOuter;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawQuad(Texture2D texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight,
|
currentInner = nextInner;
|
||||||
ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight)
|
currentOuter = nextOuter;
|
||||||
{
|
}
|
||||||
var mesh = GetMeshBuilder(texture);
|
}
|
||||||
|
|
||||||
int i1 = mesh.AddVertex(topLeft);
|
public void DrawQuad(Texture2D texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight,
|
||||||
int i2 = mesh.AddVertex(topRight);
|
ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight)
|
||||||
int i3 = mesh.AddVertex(bottomLeft);
|
{
|
||||||
int i4 = mesh.AddVertex(bottomRight);
|
var mesh = GetMeshBuilder(texture);
|
||||||
|
|
||||||
mesh.AddTriangle(i1, i2, i3);
|
int i1 = mesh.AddVertex(topLeft);
|
||||||
mesh.AddTriangle(i3, i2, i4);
|
int i2 = mesh.AddVertex(topRight);
|
||||||
}
|
int i3 = mesh.AddVertex(bottomLeft);
|
||||||
|
int i4 = mesh.AddVertex(bottomRight);
|
||||||
public GraphicsDevice GraphicsDevice => guiRenderer.GraphicsDevice;
|
|
||||||
|
mesh.AddTriangle(i1, i2, i3);
|
||||||
|
mesh.AddTriangle(i3, i2, i4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphicsDevice GraphicsDevice => guiRenderer.GraphicsDevice;
|
||||||
}
|
}
|
0
src/AcidicGUI/Rendering/GuiMesh.cs
Normal file → Executable file
0
src/AcidicGUI/Rendering/GuiMesh.cs
Normal file → Executable file
0
src/AcidicGUI/Rendering/GuiMeshBuilder.cs
Normal file → Executable file
0
src/AcidicGUI/Rendering/GuiMeshBuilder.cs
Normal file → Executable file
448
src/AcidicGUI/Rendering/Vertex.cs
Normal file → Executable file
448
src/AcidicGUI/Rendering/Vertex.cs
Normal file → Executable file
|
@ -1,229 +1,221 @@
|
||||||
using AcidicGUI.Effects;
|
using AcidicGUI.Effects;
|
||||||
using AcidicGUI.Layout;
|
using AcidicGUI.Layout;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
|
namespace AcidicGUI.Rendering;
|
||||||
namespace AcidicGUI.Rendering;
|
|
||||||
|
public sealed class GuiRenderer
|
||||||
public sealed class GuiRenderer
|
{
|
||||||
{
|
private GuiBatch? whiteBatch;
|
||||||
private readonly Dictionary<Texture2D, GuiBatch> batches = new();
|
private readonly Dictionary<Texture2D, GuiBatch> batches = new();
|
||||||
private readonly IGuiContext context;
|
private readonly IGuiContext context;
|
||||||
private readonly Stack<Matrix> previousMatrices = new();
|
private float layer;
|
||||||
private Matrix currentMatrix = Matrix.Identity;
|
|
||||||
private GuiBatch? whiteBatch;
|
public GuiRenderer(IGuiContext context)
|
||||||
private float layer;
|
{
|
||||||
|
this.context = context;
|
||||||
public GuiRenderer(IGuiContext context)
|
}
|
||||||
{
|
|
||||||
this.context = context;
|
public float Layer => layer;
|
||||||
}
|
|
||||||
|
public void SetLayer(float newLayer)
|
||||||
public float Layer => layer;
|
{
|
||||||
|
layer = newLayer;
|
||||||
public void PushTransformMatrix(Matrix matrix)
|
}
|
||||||
{
|
|
||||||
previousMatrices.Push(currentMatrix);
|
public void PushLayer()
|
||||||
currentMatrix *= matrix;
|
{
|
||||||
}
|
layer += 0.5f;
|
||||||
|
}
|
||||||
public void PopTransformMatrix()
|
|
||||||
{
|
public void PopLayer()
|
||||||
if (previousMatrices.Count == 0)
|
{
|
||||||
{
|
layer--;
|
||||||
currentMatrix = Matrix.Identity;
|
}
|
||||||
return;
|
|
||||||
}
|
public void RenderGuiMesh(GuiMesh mesh)
|
||||||
|
{
|
||||||
currentMatrix = previousMatrices.Pop();
|
foreach (GuiSubMesh subMesh in mesh.SubMeshes)
|
||||||
}
|
{
|
||||||
|
SubmitSubMesh(subMesh);
|
||||||
public void RenderGuiMesh(GuiMesh mesh)
|
}
|
||||||
{
|
}
|
||||||
foreach (GuiSubMesh subMesh in mesh.SubMeshes)
|
|
||||||
{
|
public int GetVertexCount(Texture2D? texture)
|
||||||
SubmitSubMesh(subMesh);
|
{
|
||||||
}
|
if (texture == null)
|
||||||
}
|
{
|
||||||
|
if (whiteBatch==null)
|
||||||
public int GetVertexCount(Texture2D? texture)
|
whiteBatch = new GuiBatch(context, GraphicsDevice, null);
|
||||||
{
|
|
||||||
if (texture == null)
|
return whiteBatch.VertexCount;
|
||||||
{
|
}
|
||||||
if (whiteBatch==null)
|
|
||||||
whiteBatch = new GuiBatch(context, GraphicsDevice, null);
|
if (!batches.TryGetValue(texture, out GuiBatch? batch))
|
||||||
|
{
|
||||||
return whiteBatch.VertexCount;
|
batch = new GuiBatch(context, GraphicsDevice, texture);
|
||||||
}
|
batches.Add(texture, batch);
|
||||||
|
}
|
||||||
if (!batches.TryGetValue(texture, out GuiBatch? batch))
|
|
||||||
{
|
return batch.VertexCount;
|
||||||
batch = new GuiBatch(context, GraphicsDevice, texture);
|
}
|
||||||
batches.Add(texture, batch);
|
|
||||||
}
|
private void SubmitSubMesh(GuiSubMesh subMesh)
|
||||||
|
{
|
||||||
return batch.VertexCount;
|
if (subMesh.Texture != null)
|
||||||
}
|
{
|
||||||
|
if (!batches.TryGetValue(subMesh.Texture, out GuiBatch? batch))
|
||||||
private void SubmitSubMesh(GuiSubMesh subMesh)
|
{
|
||||||
{
|
batch = new GuiBatch(context, GraphicsDevice, subMesh.Texture);
|
||||||
if (subMesh.Texture != null)
|
batches.Add(subMesh.Texture, batch);
|
||||||
{
|
}
|
||||||
if (!batches.TryGetValue(subMesh.Texture, out GuiBatch? batch))
|
|
||||||
{
|
batch.Submit(subMesh);
|
||||||
batch = new GuiBatch(context, GraphicsDevice, subMesh.Texture);
|
return;
|
||||||
batches.Add(subMesh.Texture, batch);
|
}
|
||||||
}
|
|
||||||
|
if (whiteBatch==null)
|
||||||
batch.Submit(subMesh);
|
whiteBatch = new GuiBatch(context, GraphicsDevice, null);
|
||||||
return;
|
|
||||||
}
|
whiteBatch.Submit(subMesh);
|
||||||
|
}
|
||||||
if (whiteBatch==null)
|
|
||||||
whiteBatch = new GuiBatch(context, GraphicsDevice, null);
|
public void RenderBatches(IEffect? effectOverride = null, float opacity = 1, LayoutRect? clipRect = null)
|
||||||
|
{
|
||||||
whiteBatch.Submit(subMesh);
|
whiteBatch?.DrawBatch(effectOverride, opacity, clipRect);
|
||||||
}
|
|
||||||
|
foreach (GuiBatch batch in batches.Values)
|
||||||
public void RenderBatches(IEffect? effectOverride = null, float opacity = 1, LayoutRect? clipRect = null)
|
batch.DrawBatch(effectOverride, opacity, clipRect);
|
||||||
{
|
}
|
||||||
whiteBatch?.DrawBatch(effectOverride, opacity, clipRect, currentMatrix);
|
|
||||||
|
public void Grab(RenderTarget2D destination)
|
||||||
foreach (GuiBatch batch in batches.Values)
|
{
|
||||||
batch.DrawBatch(effectOverride, opacity, clipRect, currentMatrix);
|
context.Grab(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Grab(RenderTarget2D destination)
|
public void Restore()
|
||||||
{
|
{
|
||||||
context.Grab(destination);
|
context.RestoreRenderState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restore()
|
public GraphicsDevice GraphicsDevice => context.GraphicsDevice;
|
||||||
{
|
}
|
||||||
context.RestoreRenderState();
|
|
||||||
}
|
public sealed class GrowingList<T>
|
||||||
|
{
|
||||||
public GraphicsDevice GraphicsDevice => context.GraphicsDevice;
|
private readonly List<T> list = new();
|
||||||
}
|
private int insertIndex;
|
||||||
|
|
||||||
public sealed class GrowingList<T>
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
{
|
||||||
private readonly List<T> list = new();
|
return list.GetEnumerator();
|
||||||
private int insertIndex;
|
}
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
public void AddRange(IEnumerable<T> items)
|
||||||
{
|
{
|
||||||
return list.GetEnumerator();
|
foreach (T item in items)
|
||||||
}
|
Add(item);
|
||||||
|
}
|
||||||
public void AddRange(IEnumerable<T> items)
|
|
||||||
{
|
public void Add(T item)
|
||||||
foreach (T item in items)
|
{
|
||||||
Add(item);
|
if (insertIndex == list.Count)
|
||||||
}
|
list.Add(item);
|
||||||
|
else
|
||||||
public void Add(T item)
|
list[insertIndex] = item;
|
||||||
{
|
|
||||||
if (insertIndex == list.Count)
|
insertIndex++;
|
||||||
list.Add(item);
|
}
|
||||||
else
|
|
||||||
list[insertIndex] = item;
|
public void Clear()
|
||||||
|
{
|
||||||
insertIndex++;
|
insertIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public int Count => insertIndex;
|
||||||
{
|
|
||||||
insertIndex = 0;
|
public T[] ToArray()
|
||||||
}
|
{
|
||||||
|
return list.ToArray().AsSpan().Slice(0, insertIndex).ToArray();
|
||||||
public int Count => insertIndex;
|
}
|
||||||
|
}
|
||||||
public T[] ToArray()
|
|
||||||
{
|
public sealed class GuiBatch
|
||||||
return list.ToArray().AsSpan().Slice(0, insertIndex).ToArray();
|
{
|
||||||
}
|
private readonly GraphicsDevice device;
|
||||||
}
|
private VertexBuffer? vertexBuffer;
|
||||||
|
private IndexBuffer? indexBuffer;
|
||||||
public sealed class GuiBatch
|
private readonly Texture2D? texture;
|
||||||
{
|
private readonly IGuiContext context;
|
||||||
private readonly GraphicsDevice device;
|
private readonly GrowingList<VertexPositionColorTexture> cpuVertices = new();
|
||||||
private VertexBuffer? vertexBuffer;
|
private readonly GrowingList<int> cpuIndices = new();
|
||||||
private IndexBuffer? indexBuffer;
|
|
||||||
private readonly Texture2D? texture;
|
private int vertexDirtiness;
|
||||||
private readonly IGuiContext context;
|
private int indexDirtiness;
|
||||||
private readonly GrowingList<VertexPositionColorTexture> cpuVertices = new();
|
private bool dirty;
|
||||||
private readonly GrowingList<int> cpuIndices = new();
|
|
||||||
|
public GuiBatch(IGuiContext context, GraphicsDevice device, Texture2D? texture)
|
||||||
private int vertexDirtiness;
|
{
|
||||||
private int indexDirtiness;
|
this.context = context;
|
||||||
private bool dirty;
|
this.device = device;
|
||||||
|
this.texture = texture;
|
||||||
public GuiBatch(IGuiContext context, GraphicsDevice device, Texture2D? texture)
|
}
|
||||||
{
|
|
||||||
this.context = context;
|
public int VertexCount => cpuVertices.Count;
|
||||||
this.device = device;
|
|
||||||
this.texture = texture;
|
public void Submit(GuiSubMesh subMesh)
|
||||||
}
|
{
|
||||||
|
if (subMesh.IsNew)
|
||||||
public int VertexCount => cpuVertices.Count;
|
{
|
||||||
|
subMesh.MarkAsOld();
|
||||||
public void Submit(GuiSubMesh subMesh)
|
if (!dirty)
|
||||||
{
|
{
|
||||||
if (subMesh.Vertices.Length == 0 || subMesh.Indices.Length == 0)
|
vertexDirtiness = cpuVertices.Count;
|
||||||
return;
|
indexDirtiness = cpuIndices.Count;
|
||||||
|
}
|
||||||
if (subMesh.IsNew)
|
|
||||||
{
|
dirty = true;
|
||||||
subMesh.MarkAsOld();
|
}
|
||||||
if (!dirty)
|
|
||||||
{
|
cpuVertices.AddRange(subMesh.Vertices);
|
||||||
vertexDirtiness = cpuVertices.Count;
|
cpuIndices.AddRange(subMesh.Indices);
|
||||||
indexDirtiness = cpuIndices.Count;
|
}
|
||||||
}
|
|
||||||
|
public void DrawBatch(IEffect? effectOverride, float opacity, LayoutRect? clipRect)
|
||||||
dirty = true;
|
{
|
||||||
}
|
if (cpuIndices.Count == 0 || cpuVertices.Count == 0)
|
||||||
|
return;
|
||||||
cpuVertices.AddRange(subMesh.Vertices);
|
|
||||||
cpuIndices.AddRange(subMesh.Indices);
|
if (vertexBuffer == null || vertexBuffer.VertexCount < cpuVertices.Count)
|
||||||
}
|
{
|
||||||
|
vertexBuffer?.Dispose();
|
||||||
public void DrawBatch(IEffect? effectOverride, float opacity, LayoutRect? clipRect, Matrix widgetTransform)
|
dirty = true;
|
||||||
{
|
vertexDirtiness = 0;
|
||||||
if (cpuIndices.Count == 0 || cpuVertices.Count == 0)
|
vertexBuffer = new VertexBuffer(device, typeof(VertexPositionColorTexture), cpuVertices.Count, BufferUsage.None);
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (vertexBuffer == null || vertexBuffer.VertexCount < cpuVertices.Count)
|
if (indexBuffer == null || indexBuffer.IndexCount < cpuIndices.Count)
|
||||||
{
|
{
|
||||||
vertexBuffer?.Dispose();
|
indexBuffer?.Dispose();
|
||||||
dirty = true;
|
dirty = true;
|
||||||
vertexDirtiness = 0;
|
indexDirtiness = 0;
|
||||||
vertexBuffer = new VertexBuffer(device, typeof(VertexPositionColorTexture), cpuVertices.Count, BufferUsage.None);
|
indexBuffer = new IndexBuffer(device, typeof(int), cpuIndices.Count, BufferUsage.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indexBuffer == null || indexBuffer.IndexCount < cpuIndices.Count)
|
if (dirty)
|
||||||
{
|
{
|
||||||
indexBuffer?.Dispose();
|
var vertexData = cpuVertices.ToArray();
|
||||||
dirty = true;
|
var indexData = cpuIndices.ToArray();
|
||||||
indexDirtiness = 0;
|
|
||||||
indexBuffer = new IndexBuffer(device, typeof(int), cpuIndices.Count, BufferUsage.None);
|
vertexBuffer.SetData(vertexData, vertexDirtiness, vertexData.Length - vertexDirtiness);
|
||||||
}
|
indexBuffer.SetData(indexData, indexDirtiness, indexData.Length - indexDirtiness);
|
||||||
|
|
||||||
if (dirty)
|
dirty = false;
|
||||||
{
|
}
|
||||||
var vertexData = cpuVertices.ToArray();
|
|
||||||
var indexData = cpuIndices.ToArray();
|
context.Render(vertexBuffer, indexBuffer, 0, cpuIndices.Count / 3, texture, clipRect, effectOverride, opacity);
|
||||||
|
|
||||||
vertexBuffer.SetData(vertexData, vertexDirtiness, vertexData.Length - vertexDirtiness);
|
cpuVertices.Clear();
|
||||||
indexBuffer.SetData(indexData, indexDirtiness, indexData.Length - indexDirtiness);
|
cpuIndices.Clear();
|
||||||
|
}
|
||||||
dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Render(vertexBuffer, indexBuffer, 0, cpuIndices.Count / 3, texture, clipRect, effectOverride, opacity, widgetTransform);
|
|
||||||
|
|
||||||
cpuVertices.Clear();
|
|
||||||
cpuIndices.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
0
src/AcidicGUI/Sdl@platform.cs
Normal file → Executable file
0
src/AcidicGUI/Sdl@platform.cs
Normal file → Executable file
0
src/AcidicGUI/TextRendering/DynamicFont.cs
Normal file → Executable file
0
src/AcidicGUI/TextRendering/DynamicFont.cs
Normal file → Executable file
0
src/AcidicGUI/TextRendering/Font.cs
Normal file → Executable file
0
src/AcidicGUI/TextRendering/Font.cs
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue