From 258deb99b0c412312e847d255059a371c1df4cd1 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Fri, 15 Dec 2023 22:30:58 -0300 Subject: [PATCH 01/48] Added spacer item --- LemonUI/Menus/NativeSpacerItem.cs | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 LemonUI/Menus/NativeSpacerItem.cs diff --git a/LemonUI/Menus/NativeSpacerItem.cs b/LemonUI/Menus/NativeSpacerItem.cs new file mode 100644 index 0000000..f017a4e --- /dev/null +++ b/LemonUI/Menus/NativeSpacerItem.cs @@ -0,0 +1,47 @@ +using System.Drawing; +using GTA.UI; + +namespace LemonUI.Menus +{ + /// + /// An item used to have a space between the items with text. + /// + public class NativeSpacerItem : NativeItem + { + #region Constructor + + /// + /// Creates a new Spacer with no text. + /// + public NativeSpacerItem() : this(string.Empty) + { + } + /// + /// Creates a new Spacer with a specific title. + /// + /// The title of the item. + public NativeSpacerItem(string title) : base(title, string.Empty, string.Empty) + { + this.title.Alignment = Alignment.Center; + } + + #endregion + + #region Function + + /// + public override void Recalculate(PointF pos, SizeF size, bool selected) + { + base.Recalculate(pos, size, selected); + + title.Position = new PointF(pos.X + (size.Width * 0.5f), title.Position.Y); + } + /// + public override void Draw() + { + title.Draw(); + } + + #endregion + } +} From 9bf8b3a73bcc9f5fb3a42a60c6418266795d6368 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 01:42:06 -0300 Subject: [PATCH 02/48] Moved extensions to a single class in the Tools namespace --- LemonUI/Extensions/FloatExtensions.cs | 31 +++--------- LemonUI/Extensions/PointExtensions.cs | 18 ++----- LemonUI/Extensions/SizeExtensions.cs | 18 ++----- LemonUI/Tools/Extensions.cs | 73 +++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 LemonUI/Tools/Extensions.cs diff --git a/LemonUI/Extensions/FloatExtensions.cs b/LemonUI/Extensions/FloatExtensions.cs index 81bb74e..0b82150 100644 --- a/LemonUI/Extensions/FloatExtensions.cs +++ b/LemonUI/Extensions/FloatExtensions.cs @@ -1,53 +1,36 @@ +using System; + namespace LemonUI.Extensions { /// /// Extensions for the float class. /// + [Obsolete("Please use LemonUI.Tools.Extensions instead.", true)] public static class FloatExtensions { - #region Extensions - /// /// Converts an absolute X or Width float to a relative one. /// /// The float to convert. /// A relative float between 0 and 1. - public static float ToXRelative(this float fin) - { - Screen.ToRelative(fin, 0, out float fout, out _); - return fout; - } + public static float ToXRelative(this float fin) => Tools.Extensions.ToXRelative(fin); /// /// Converts an absolute Y or Height float to a relative one. /// /// The float to convert. /// A relative float between 0 and 1. - public static float ToYRelative(this float fin) - { - Screen.ToRelative(0, fin, out _, out float fout); - return fout; - } + public static float ToYRelative(this float fin) => Tools.Extensions.ToYRelative(fin); /// /// Converts an relative X or Width float to an absolute one. /// /// The float to convert. /// An absolute float. - public static float ToXAbsolute(this float fin) - { - Screen.ToAbsolute(fin, 0, out float fout, out _); - return fout; - } + public static float ToXAbsolute(this float fin) => Tools.Extensions.ToXAbsolute(fin); /// /// Converts an relative Y or Height float to an absolute one. /// /// The float to convert. /// An absolute float. - public static float ToYAbsolute(this float fin) - { - Screen.ToAbsolute(0, fin, out _, out float fout); - return fout; - } - - #endregion + public static float ToYAbsolute(this float fin) => Tools.Extensions.ToYAbsolute(fin); } } diff --git a/LemonUI/Extensions/PointExtensions.cs b/LemonUI/Extensions/PointExtensions.cs index 5b81adf..5d55083 100644 --- a/LemonUI/Extensions/PointExtensions.cs +++ b/LemonUI/Extensions/PointExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Drawing; namespace LemonUI.Extensions @@ -5,31 +6,20 @@ namespace LemonUI.Extensions /// /// Extensions for the Point and PointF classes. /// + [Obsolete("Please use LemonUI.Tools.Extensions instead.", true)] public static class PointExtensions { - #region Extensions - /// /// Converts an absolute 1080-based position into a relative one. /// /// The absolute PointF. /// A new PointF with relative values. - public static PointF ToRelative(this PointF point) - { - Screen.ToRelative(point.X, point.Y, out float x, out float y); - return new PointF(x, y); - } + public static PointF ToRelative(this PointF point) => Tools.Extensions.ToRelative(point); /// /// Converts a normalized 0-1 position into an absolute one. /// /// The relative PointF. /// A new PointF with absolute values. - public static PointF ToAbsolute(this PointF point) - { - Screen.ToAbsolute(point.X, point.Y, out float x, out float y); - return new PointF(x, y); - } - - #endregion + public static PointF ToAbsolute(this PointF point) => Tools.Extensions.ToAbsolute(point); } } diff --git a/LemonUI/Extensions/SizeExtensions.cs b/LemonUI/Extensions/SizeExtensions.cs index e2a893e..5d86e1e 100644 --- a/LemonUI/Extensions/SizeExtensions.cs +++ b/LemonUI/Extensions/SizeExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Drawing; namespace LemonUI.Extensions @@ -5,31 +6,20 @@ namespace LemonUI.Extensions /// /// Extensions for the Size and SizeF classes. /// + [Obsolete("Please use LemonUI.Tools.Extensions instead.", true)] public static class SizeExtensions { - #region Extensions - /// /// Converts an absolute 1080-based size into a relative one. /// /// The absolute SizeF. /// A new SizeF with relative values. - public static SizeF ToRelative(this SizeF size) - { - Screen.ToRelative(size.Width, size.Height, out float width, out float height); - return new SizeF(width, height); - } + public static SizeF ToRelative(this SizeF size) => Tools.Extensions.ToRelative(size); /// /// Converts a normalized 0-1 size into an absolute one. /// /// The relative SizeF. /// A new SizeF with absolute values. - public static SizeF ToAbsolute(this SizeF size) - { - Screen.ToAbsolute(size.Width, size.Height, out float width, out float height); - return new SizeF(width, height); - } - - #endregion + public static SizeF ToAbsolute(this SizeF size) => Tools.Extensions.ToAbsolute(size); } } diff --git a/LemonUI/Tools/Extensions.cs b/LemonUI/Tools/Extensions.cs new file mode 100644 index 0000000..70461c0 --- /dev/null +++ b/LemonUI/Tools/Extensions.cs @@ -0,0 +1,73 @@ +using System.Drawing; + +namespace LemonUI.Tools +{ + /// + /// Extensions for converting values between relative and absolute. + /// + public static class Extensions + { + #region Float + + /// + /// Converts an absolute X or Width float to a relative one. + /// + /// The float to convert. + /// A relative float between 0 and 1. + public static float ToXRelative(this float x) => x / (1080f * GameScreen.AspectRatio); + /// + /// Converts an absolute Y or Height float to a relative one. + /// + /// The float to convert. + /// A relative float between 0 and 1. + public static float ToYRelative(this float y) => y / 1080f; + /// + /// Converts an relative X or Width float to an absolute one. + /// + /// The float to convert. + /// An absolute float. + public static float ToXAbsolute(this float x) => (1080f * GameScreen.AspectRatio) * x; + /// + /// Converts an relative Y or Height float to an absolute one. + /// + /// The float to convert. + /// An absolute float. + public static float ToYAbsolute(this float y) => 1080f * y; + + #endregion + + #region PointF + + /// + /// Converts an absolute 1080-based position into a relative one. + /// + /// The absolute PointF. + /// A new PointF with relative values. + public static PointF ToRelative(this PointF point) => new PointF(point.X.ToXRelative(), point.Y.ToYRelative()); + /// + /// Converts a normalized 0-1 position into an absolute one. + /// + /// The relative PointF. + /// A new PointF with absolute values. + public static PointF ToAbsolute(this PointF point) => new PointF(point.X.ToXAbsolute(), point.Y.ToYAbsolute()); + + #endregion + + #region SizeF + + /// + /// Converts an absolute 1080-based size into a relative one. + /// + /// The absolute SizeF. + /// A new SizeF with relative values. + public static SizeF ToRelative(this SizeF size) => new SizeF(size.Width.ToXAbsolute(), size.Height.ToYAbsolute()); + /// + /// Converts a normalized 0-1 size into an absolute one. + /// + /// The relative SizeF. + /// A new SizeF with absolute values. + public static SizeF ToAbsolute(this SizeF size) => new SizeF(size.Width.ToXRelative(), size.Height.ToYRelative()); + + #endregion + } +} From c560e24087bbe3a661d4bc64b71dbd7e6f456774 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 01:42:50 -0300 Subject: [PATCH 03/48] Split the Screen class into the SafeZone and GameScreen classes They are now in Tools --- LemonUI/Screen.cs | 184 ++++------------------------------- LemonUI/Tools/GameScreen.cs | 123 ++++++++++++++++++++++++ LemonUI/Tools/SafeZone.cs | 186 ++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+), 168 deletions(-) create mode 100644 LemonUI/Tools/GameScreen.cs create mode 100644 LemonUI/Tools/SafeZone.cs diff --git a/LemonUI/Screen.cs b/LemonUI/Screen.cs index 27acfe7..52df2b2 100644 --- a/LemonUI/Screen.cs +++ b/LemonUI/Screen.cs @@ -16,15 +16,16 @@ using AltV.Net.Client; using LemonUI.Elements; #endif -using LemonUI.Extensions; using System; using System.Drawing; +using LemonUI.Tools; namespace LemonUI { /// /// Contains a set of tools to work with the screen information. /// + [Obsolete("Use the LemonUI.Tools and LemonUI.Math namespaces.")] public static class Screen { #region Properties @@ -32,24 +33,8 @@ public static class Screen /// /// The Aspect Ratio of the screen resolution. /// - public static float AspectRatio - { - get - { -#if FIVEM - return API.GetAspectRatio(false); -#elif RAGEMP - return Invoker.Invoke(Natives.GetAspectRatio); -#elif RPH - return NativeFunction.CallByHash(0xF1307EF624A80D87, false); -#elif SHVDN3 || SHVDNC - return Function.Call(Hash.GET_ASPECT_RATIO, false); -#elif ALTV - return Alt.Natives.GetAspectRatio(false); -#endif - } - } - + public static float AspectRatio => GameScreen.AspectRatio; + #if ALTV /// /// Gets the actual Screen resolution the game is being rendered at @@ -64,33 +49,10 @@ public static Size Resolution } } #endif - /// /// The location of the cursor on screen between 0 and 1. /// - public static PointF CursorPositionRelative - { - get - { -#if FIVEM - float cursorX = API.GetControlNormal(0, (int)Control.CursorX); - float cursorY = API.GetControlNormal(0, (int)Control.CursorY); -#elif ALTV - float cursorX = Alt.Natives.GetControlNormal(0, (int)Control.CursorX); - float cursorY = Alt.Natives.GetControlNormal(0, (int)Control.CursorY); -#elif RAGEMP - float cursorX = Invoker.Invoke(Natives.GetControlNormal, 0, (int)Control.CursorX); - float cursorY = Invoker.Invoke(Natives.GetControlNormal, 0, (int)Control.CursorY); -#elif RPH - float cursorX = NativeFunction.CallByHash(0xEC3C9B8D5327B563, 0, (int)Control.CursorX); - float cursorY = NativeFunction.CallByHash(0xEC3C9B8D5327B563, 0, (int)Control.CursorY); -#elif SHVDN3 || SHVDNC - float cursorX = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorX); - float cursorY = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorY); -#endif - return new PointF(cursorX, cursorY); - } - } + public static PointF CursorPositionRelative => GameScreen.Cursor.ToRelative(); #endregion @@ -105,11 +67,8 @@ public static PointF CursorPositionRelative /// The value of Y scaled to 1080p. public static void ToAbsolute(float relativeX, float relativeY, out float absoluteX, out float absoluteY) { - // Get the real width based on the aspect ratio - float width = 1080f * AspectRatio; - // And save the correct values - absoluteX = width * relativeX; - absoluteY = 1080f * relativeY; + absoluteX = relativeX.ToXAbsolute(); + absoluteY = relativeY.ToYAbsolute(); } /// /// Converts a 1080p-based resolution into relative values. @@ -120,11 +79,8 @@ public static void ToAbsolute(float relativeX, float relativeY, out float absolu /// The value of Y converted to relative. public static void ToRelative(float absoluteX, float absoluteY, out float relativeX, out float relativeY) { - // Get the real width based on the aspect ratio - float width = 1080f * AspectRatio; - // And save the correct values - relativeX = absoluteX / width; - relativeY = absoluteY / 1080f; + relativeX = absoluteX.ToXRelative(); + relativeY = absoluteY.ToYRelative(); } /// /// Checks if the cursor is inside of the specified area. @@ -149,16 +105,9 @@ public static void ToRelative(float absoluteX, float absoluteY, out float relati /// if the cursor is in the specified bounds, otherwise. public static bool IsCursorInArea(float x, float y, float width, float height) { - PointF cursor = CursorPositionRelative; - - ToRelative(width, height, out float realWidth, out float realHeight); - + // intentionally kept this way to avoid breaking backwards compatibility PointF realPos = GetRealPosition(x, y).ToRelative(); - - bool isX = cursor.X >= realPos.X && cursor.X <= realPos.X + realWidth; - bool isY = cursor.Y > realPos.Y && cursor.Y < realPos.Y + realHeight; - - return isX && isY; + return GameScreen.IsCursorInArea(realPos.X, realPos.Y, width, height); } /// /// Converts the specified position into one that is aware of . @@ -172,128 +121,27 @@ public static bool IsCursorInArea(float x, float y, float width, float height) /// The 1080p based X position. /// The 1080p based Y position. /// A new 1080p based position that is aware of the the Alignment. - public static PointF GetRealPosition(float x, float y) - { - // Convert the resolution to relative - ToRelative(x, y, out float relativeX, out float relativeY); - // Request the real location of the position - float realX = 0, realY = 0; -#if FIVEM - API.GetScriptGfxPosition(relativeX, relativeY, ref realX, ref realY); -#elif ALTV - Alt.Natives.GetScriptGfxAlignPosition(relativeX, relativeY, ref realX, ref realY); -#elif RAGEMP - FloatReference argX = new FloatReference(); - FloatReference argY = new FloatReference(); - Invoker.Invoke(0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); - realX = argX.Value; - realY = argY.Value; -#elif RPH - using (NativePointer argX = new NativePointer(4)) - using (NativePointer argY = new NativePointer(4)) - { - NativeFunction.CallByHash(0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); - realX = argX.GetValue(); - realY = argY.GetValue(); - } -#elif SHVDN3 || SHVDNC - using (OutputArgument argX = new OutputArgument()) - using (OutputArgument argY = new OutputArgument()) - { - Function.Call((Hash)0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); // _GET_SCRIPT_GFX_POSITION - realX = argX.GetResult(); - realY = argY.GetResult(); - } -#endif - // And return it converted to absolute - ToAbsolute(realX, realY, out float absoluteX, out float absoluteY); - return new PointF(absoluteX, absoluteY); - } + public static PointF GetRealPosition(float x, float y) => SafeZone.GetSafePosition(x, y); /// /// Shows the cursor during the current game frame. /// - public static void ShowCursorThisFrame() - { -#if FIVEM - API.SetMouseCursorActiveThisFrame(); -#elif ALTV - Alt.Natives.SetMouseCursorThisFrame(); -#elif RAGEMP - Invoker.Invoke(0xAAE7CE1D63167423); -#elif RPH - NativeFunction.CallByHash(0xAAE7CE1D63167423); -#elif SHVDN3 || SHVDNC - Function.Call(Hash.SET_MOUSE_CURSOR_THIS_FRAME); -#endif - } + public static void ShowCursorThisFrame() => GameScreen.ShowCursorThisFrame(); /// /// Sets the alignment of game elements like , and . /// /// The Horizontal alignment of the items. /// The vertical alignment of the items. - public static void SetElementAlignment(Alignment horizontal, GFXAlignment vertical) - { - // If the enum value is not correct, raise an exception - if (!Enum.IsDefined(typeof(Alignment), horizontal)) - { - throw new ArgumentException("Alignment is not one of the allowed values (Left, Right, Center).", nameof(horizontal)); - } - - // Otherwise, just call the correct function - switch (horizontal) - { - case Alignment.Left: - SetElementAlignment(GFXAlignment.Left, vertical); - break; - case Alignment.Right: - SetElementAlignment(GFXAlignment.Right, vertical); - break; - case Alignment.Center: - SetElementAlignment(GFXAlignment.Right, vertical); - break; - } - } + public static void SetElementAlignment(Alignment horizontal, GFXAlignment vertical) => SafeZone.SetAlignment(horizontal, vertical); /// /// Sets the alignment of game elements like , and . /// /// The Horizontal alignment of the items. /// The vertical alignment of the items. - public static void SetElementAlignment(GFXAlignment horizontal, GFXAlignment vertical) - { -#if FIVEM - API.SetScriptGfxAlign((int)horizontal, (int)vertical); - API.SetScriptGfxAlignParams(0, 0, 0, 0); -#elif ALTV - Alt.Natives.SetScriptGfxAlign((int)horizontal, (int)vertical); - Alt.Natives.SetScriptGfxAlignParams(0, 0, 0, 0); -#elif RAGEMP - Invoker.Invoke(0xB8A850F20A067EB6, (int)horizontal, (int)vertical); - Invoker.Invoke(0xF5A2C681787E579D, 0, 0, 0, 0); -#elif RPH - NativeFunction.CallByHash(0xB8A850F20A067EB6, (int)horizontal, (int)vertical); - NativeFunction.CallByHash(0xF5A2C681787E579D, 0, 0, 0, 0); -#elif SHVDN3 || SHVDNC - Function.Call(Hash.SET_SCRIPT_GFX_ALIGN, (int)horizontal, (int)vertical); - Function.Call(Hash.SET_SCRIPT_GFX_ALIGN_PARAMS, 0, 0, 0, 0); -#endif - } + public static void SetElementAlignment(GFXAlignment horizontal, GFXAlignment vertical) => SafeZone.SetAlignment(horizontal, vertical); /// /// Resets the alignment of the game elements. /// - public static void ResetElementAlignment() - { -#if FIVEM - API.ResetScriptGfxAlign(); -#elif ALTV - Alt.Natives.ResetScriptGfxAlign(); -#elif RAGEMP - Invoker.Invoke(0xE3A3DB414A373DAB); -#elif RPH - NativeFunction.CallByHash(0xE3A3DB414A373DAB); -#elif SHVDN3 || SHVDNC - Function.Call(Hash.RESET_SCRIPT_GFX_ALIGN); -#endif - } + public static void ResetElementAlignment() => SafeZone.ResetAlignment(); #endregion } diff --git a/LemonUI/Tools/GameScreen.cs b/LemonUI/Tools/GameScreen.cs new file mode 100644 index 0000000..5c15b6b --- /dev/null +++ b/LemonUI/Tools/GameScreen.cs @@ -0,0 +1,123 @@ +#if FIVEM +using CitizenFX.Core; +using CitizenFX.Core.Native; +using CitizenFX.Core.UI; +#elif RAGEMP +using RAGE.Game; +#elif RPH +using Rage; +using Rage.Native; +using Control = Rage.GameControl; +#elif SHVDN3 || SHVDNC +using GTA; +using GTA.Native; +#elif ALTV +using AltV.Net.Client; +using LemonUI.Elements; +#endif +using System.Drawing; + +namespace LemonUI.Tools +{ + /// + /// The screen of the game being rendered. + /// + public static class GameScreen + { + #region Properties + + /// + /// The Aspect Ratio of the screen. + /// + public static float AspectRatio + { + get + { +#if FIVEM + return API.GetAspectRatio(false); +#elif RAGEMP + return Invoker.Invoke(Natives.GetAspectRatio); +#elif RPH + return NativeFunction.CallByHash(0xF1307EF624A80D87, false); +#elif SHVDN3 || SHVDNC + return Function.Call(Hash.GET_ASPECT_RATIO, false); +#elif ALTV + return Alt.Natives.GetAspectRatio(false); +#endif + } + } + /// + /// The location of the cursor on screen between 0 and 1. + /// + public static PointF Cursor + { + get + { +#if FIVEM + float cursorX = API.GetControlNormal(0, (int)Control.CursorX); + float cursorY = API.GetControlNormal(0, (int)Control.CursorY); +#elif ALTV + float cursorX = Alt.Natives.GetControlNormal(0, (int)Control.CursorX); + float cursorY = Alt.Natives.GetControlNormal(0, (int)Control.CursorY); +#elif RAGEMP + float cursorX = Invoker.Invoke(Natives.GetControlNormal, 0, (int)Control.CursorX); + float cursorY = Invoker.Invoke(Natives.GetControlNormal, 0, (int)Control.CursorY); +#elif RPH + float cursorX = NativeFunction.CallByHash(0xEC3C9B8D5327B563, 0, (int)Control.CursorX); + float cursorY = NativeFunction.CallByHash(0xEC3C9B8D5327B563, 0, (int)Control.CursorY); +#elif SHVDN3 || SHVDNC + float cursorX = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorX); + float cursorY = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorY); +#endif + return new PointF(cursorX.ToXAbsolute(), cursorY.ToYAbsolute()); + } + } + + #endregion + + #region Functions + + /// + /// Checks if the cursor is inside of the absolute area. + /// + /// The absolute position. + /// The absolute size of the area. + /// if the cursor is in the specified bounds, otherwise. + public static bool IsCursorInArea(PointF pos, SizeF size) => IsCursorInArea(pos.X, pos.Y, size.Width, size.Height); + /// + /// Checks if the cursor is inside of the absolute area. + /// + /// The absolute X position. + /// The absolute Y position. + /// The absolute width of the area. + /// The absolute height of the area. + /// if the cursor is in the specified bounds, otherwise. + public static bool IsCursorInArea(float x, float y, float width, float height) + { + PointF cursorPosition = Cursor; + + bool isX = cursorPosition.X >= x && cursorPosition.X <= x + width; + bool isY = cursorPosition.Y > y && cursorPosition.Y < y + height; + return isX && isY; + } + /// + /// Shows the cursor during the current game frame. + /// + public static void ShowCursorThisFrame() + { +#if FIVEM + API.SetMouseCursorActiveThisFrame(); +#elif ALTV + Alt.Natives.SetMouseCursorThisFrame(); +#elif RAGEMP + Invoker.Invoke(0xAAE7CE1D63167423); +#elif RPH + NativeFunction.CallByHash(0xAAE7CE1D63167423); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.SET_MOUSE_CURSOR_THIS_FRAME); +#endif + } + + #endregion + } +} diff --git a/LemonUI/Tools/SafeZone.cs b/LemonUI/Tools/SafeZone.cs new file mode 100644 index 0000000..a146eae --- /dev/null +++ b/LemonUI/Tools/SafeZone.cs @@ -0,0 +1,186 @@ +#if ALTV +using AltV.Net.Client; +#elif RAGEMP +using RAGE.Game; +#elif FIVEM +using CitizenFX.Core.Native; +using CitizenFX.Core.UI; +#elif RPH +using Rage.Native; +#elif SHVDN3 || SHVDNC +using GTA.Native; +using GTA.UI; +#endif +using System; +using System.Drawing; + +namespace LemonUI.Tools +{ + /// + /// Tools for changing, resetting and retrieving the Safe Zone of the game. + /// + public static class SafeZone + { + #region Properties + + /// + /// The top left corner after the safe zone. + /// + public static PointF TopLeft => GetPositionAt(PointF.Empty, GFXAlignment.Left, GFXAlignment.Top); + /// + /// The top right corner after the safe zone. + /// + public static PointF TopRight => GetPositionAt(PointF.Empty, GFXAlignment.Right, GFXAlignment.Top); + /// + /// The bottom left corner after the safe zone. + /// + public static PointF BottomLeft => GetPositionAt(PointF.Empty, GFXAlignment.Left, GFXAlignment.Bottom); + /// + /// The bottom right corner after the safe zone. + /// + public static PointF BottomRight => GetPositionAt(PointF.Empty, GFXAlignment.Right, GFXAlignment.Bottom); + + #endregion + + #region Tools + + private static GFXAlignment AlignmentToGFXAlignment(Alignment alignment) + { + switch (alignment) + { + case Alignment.Left: + return GFXAlignment.Left; + case Alignment.Right: + return GFXAlignment.Right; + case Alignment.Center: + return GFXAlignment.Center; + default: + throw new ArgumentException("Alignment is not one of the allowed values (Left, Right, Center).", nameof(alignment)); + } + } + + #endregion + + #region Functions + + /// + /// Converts the specified position into one that is aware of the safe zone. + /// + /// The original 1080p based position. + /// A new 1080p based position that is aware of the the Alignment. + public static PointF GetSafePosition(PointF og) => GetSafePosition(og.X, og.Y); + /// + /// Converts the specified position into one that is aware of . + /// + /// The 1080p based X position. + /// The 1080p based Y position. + /// A new 1080p based position that is aware of the the Alignment. + public static PointF GetSafePosition(float x, float y) + { + float relativeX = x.ToXRelative(); + float relativeY = y.ToYRelative(); + + float realX = 0, realY = 0; +#if FIVEM + API.GetScriptGfxPosition(relativeX, relativeY, ref realX, ref realY); +#elif ALTV + Alt.Natives.GetScriptGfxAlignPosition(relativeX, relativeY, ref realX, ref realY); +#elif RAGEMP + FloatReference argX = new FloatReference(); + FloatReference argY = new FloatReference(); + Invoker.Invoke(0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); + realX = argX.Value; + realY = argY.Value; +#elif RPH + using (NativePointer argX = new NativePointer(4)) + using (NativePointer argY = new NativePointer(4)) + { + NativeFunction.CallByHash(0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); + realX = argX.GetValue(); + realY = argY.GetValue(); + } +#elif SHVDN3 || SHVDNC + using (OutputArgument argX = new OutputArgument()) + using (OutputArgument argY = new OutputArgument()) + { + Function.Call((Hash)0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); // _GET_SCRIPT_GFX_POSITION + realX = argX.GetResult(); + realY = argY.GetResult(); + } +#endif + + return new PointF(realX.ToXAbsolute(), realY.ToYAbsolute()); + } + /// + /// Sets the alignment for the safe zone. + /// + /// The Horizontal alignment of the items. + /// The vertical alignment of the items. + public static void SetAlignment(Alignment horizontal, GFXAlignment vertical) => SetAlignment(AlignmentToGFXAlignment(horizontal), vertical); + /// + /// Sets the alignment for the safe zone. + /// + /// The Horizontal alignment of the items. + /// The vertical alignment of the items. + public static void SetAlignment(GFXAlignment horizontal, GFXAlignment vertical) + { +#if FIVEM + API.SetScriptGfxAlign((int)horizontal, (int)vertical); + API.SetScriptGfxAlignParams(0, 0, 0, 0); +#elif ALTV + Alt.Natives.SetScriptGfxAlign((int)horizontal, (int)vertical); + Alt.Natives.SetScriptGfxAlignParams(0, 0, 0, 0); +#elif RAGEMP + Invoker.Invoke(0xB8A850F20A067EB6, (int)horizontal, (int)vertical); + Invoker.Invoke(0xF5A2C681787E579D, 0, 0, 0, 0); +#elif RPH + NativeFunction.CallByHash(0xB8A850F20A067EB6, (int)horizontal, (int)vertical); + NativeFunction.CallByHash(0xF5A2C681787E579D, 0, 0, 0, 0); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.SET_SCRIPT_GFX_ALIGN, (int)horizontal, (int)vertical); + Function.Call(Hash.SET_SCRIPT_GFX_ALIGN_PARAMS, 0, 0, 0, 0); +#endif + } + /// + /// Resets the alignment of the safe zone. + /// + public static void ResetAlignment() + { +#if FIVEM + API.ResetScriptGfxAlign(); +#elif ALTV + Alt.Natives.ResetScriptGfxAlign(); +#elif RAGEMP + Invoker.Invoke(0xE3A3DB414A373DAB); +#elif RPH + NativeFunction.CallByHash(0xE3A3DB414A373DAB); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.RESET_SCRIPT_GFX_ALIGN); +#endif + } + /// + /// Gets the specified position with the specified safe zone alignment. + /// + /// The position to get. + /// The horizontal alignment. + /// The vertical alignment. + /// The absolute safe zone alignment. + public static PointF GetPositionAt(PointF position, Alignment horizontal, GFXAlignment vertical) => GetPositionAt(position, AlignmentToGFXAlignment(horizontal), vertical); + /// + /// Gets the specified position with the specified safe zone alignment. + /// + /// The position to get. + /// The horizontal alignment. + /// The vertical alignment. + /// The absolute safe zone alignment. + public static PointF GetPositionAt(PointF position, GFXAlignment horizontal, GFXAlignment vertical) + { + SetAlignment(horizontal, vertical); + PointF pos = GetSafePosition(position); + ResetAlignment(); + return pos; + } + + #endregion + } +} From ef38f7491e32283850ef26a9f3ff4558a328466c Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 01:43:44 -0300 Subject: [PATCH 04/48] Updated existing code to use the Tools namespace --- LemonUI/Elements/BaseElement.cs | 2 +- LemonUI/Elements/ScaledText.cs | 2 +- LemonUI/Menus/NativeGridPanel.cs | 15 +++++----- LemonUI/Menus/NativeItem.cs | 3 +- LemonUI/Menus/NativeMenu.cs | 38 ++++++++++--------------- LemonUI/TimerBars/TimerBarCollection.cs | 5 ++-- 6 files changed, 28 insertions(+), 37 deletions(-) diff --git a/LemonUI/Elements/BaseElement.cs b/LemonUI/Elements/BaseElement.cs index 5522252..208911b 100644 --- a/LemonUI/Elements/BaseElement.cs +++ b/LemonUI/Elements/BaseElement.cs @@ -1,5 +1,5 @@ -using LemonUI.Extensions; using System.Drawing; +using LemonUI.Tools; namespace LemonUI.Elements { diff --git a/LemonUI/Elements/ScaledText.cs b/LemonUI/Elements/ScaledText.cs index 481c0e9..9c105a4 100644 --- a/LemonUI/Elements/ScaledText.cs +++ b/LemonUI/Elements/ScaledText.cs @@ -16,7 +16,7 @@ using System.Collections.Generic; using System.Drawing; using System.Text; -using LemonUI.Extensions; +using LemonUI.Tools; namespace LemonUI.Elements { diff --git a/LemonUI/Menus/NativeGridPanel.cs b/LemonUI/Menus/NativeGridPanel.cs index 4605b35..afc3a78 100644 --- a/LemonUI/Menus/NativeGridPanel.cs +++ b/LemonUI/Menus/NativeGridPanel.cs @@ -12,13 +12,12 @@ using Control = Rage.GameControl; #elif SHVDN3 || SHVDNC using GTA; -using GTA.Native; using GTA.UI; #endif using LemonUI.Elements; -using LemonUI.Extensions; using System; using System.Drawing; +using LemonUI.Tools; namespace LemonUI.Menus { @@ -290,16 +289,16 @@ public override void Process() if (!Controls.IsUsingController) { - if (Screen.IsCursorInArea(grid.Position, grid.Size) && Controls.IsPressed(Control.CursorAccept)) + if (GameScreen.IsCursorInArea(grid.Position, grid.Size) && Controls.IsPressed(Control.CursorAccept)) { - PointF cursor = Screen.CursorPositionRelative; - PointF pos = innerPosition.ToRelative(); + PointF cursor = GameScreen.Cursor; + PointF pos = innerPosition; PointF start = new PointF(cursor.X - pos.X, cursor.Y - pos.Y); - SizeF size = innerSize.ToRelative(); + SizeF size = innerSize; - x = start.X / size.Width; - y = start.Y / size.Height; + x = (start.X / size.Width).ToXRelative(); + y = (start.Y / size.Height).ToYRelative(); } else { diff --git a/LemonUI/Menus/NativeItem.cs b/LemonUI/Menus/NativeItem.cs index 61b7999..a36969b 100644 --- a/LemonUI/Menus/NativeItem.cs +++ b/LemonUI/Menus/NativeItem.cs @@ -11,6 +11,7 @@ using LemonUI.Elements; using System; using System.Drawing; +using LemonUI.Tools; namespace LemonUI.Menus { @@ -230,7 +231,7 @@ public ColorSet Colors /// /// If this item is being hovered. /// - public bool IsHovered => Screen.IsCursorInArea(background.Position, background.Size); + public bool IsHovered => GameScreen.IsCursorInArea(background.Position, background.Size); #endregion diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index f683773..8a8edbb 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -26,13 +26,13 @@ using Font = GTA.UI.Font; #endif using LemonUI.Elements; -using LemonUI.Extensions; using LemonUI.Scaleform; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; +using LemonUI.Tools; namespace LemonUI.Menus { @@ -950,11 +950,10 @@ public void ResetCursor() const float extraX = 35; const float extraY = 325; - // Get the correct desired position of the cursor as relative PointF pos = PointF.Empty; if (SafeZoneAware) { - Screen.SetElementAlignment(Alignment, GFXAlignment.Top); + SafeZone.SetAlignment(Alignment, GFXAlignment.Top); float x = 0; switch (Alignment) { @@ -965,8 +964,8 @@ public void ResetCursor() x = Offset.X - Width - extraX; break; } - pos = Screen.GetRealPosition(x, Offset.Y + extraY).ToRelative(); - Screen.ResetElementAlignment(); + pos = SafeZone.GetSafePosition(x, Offset.Y + extraY).ToRelative(); + SafeZone.ResetAlignment(); } else { @@ -1004,7 +1003,7 @@ private void UpdateItems() PointF pos; if (SafeZoneAware) { - Screen.SetElementAlignment(Alignment, GFXAlignment.Top); + SafeZone.SetAlignment(Alignment, GFXAlignment.Top); float x = 0; switch (Alignment) { @@ -1015,8 +1014,8 @@ private void UpdateItems() x = Offset.X - Width; break; } - pos = Screen.GetRealPosition(x, Offset.Y); - Screen.ResetElementAlignment(); + pos = SafeZone.GetSafePosition(x, Offset.Y); + SafeZone.ResetAlignment(); } else { @@ -1208,18 +1207,12 @@ private void ProcessControls() if (UseMouse && !Controls.IsUsingController) { // Enable the mouse cursor -#if FIVEM || SHVDN3 || SHVDNC || ALTV - Screen.ShowCursorThisFrame(); -#elif RAGEMP - Invoker.Invoke(Natives.ShowCursorThisFrame); -#elif RPH - NativeFunction.CallByHash(0xAAE7CE1D63167423); -#endif + GameScreen.ShowCursorThisFrame(); // If the camera should be rotated when the cursor is on the left and right sections of the screen, do so if (RotateCamera) { - if (Screen.IsCursorInArea(PointF.Empty, searchAreaSize)) + if (GameScreen.IsCursorInArea(PointF.Empty, searchAreaSize)) { #if FIVEM || SHVDN3 || SHVDNC GameplayCamera.RelativeHeading += 5; @@ -1233,7 +1226,7 @@ private void ProcessControls() Camera.RenderingCamera.Heading += 5; #endif } - else if (Screen.IsCursorInArea(searchAreaRight, searchAreaSize)) + else if (GameScreen.IsCursorInArea(searchAreaRight, searchAreaSize)) { #if FIVEM || SHVDN3 || SHVDNC GameplayCamera.RelativeHeading -= 5; @@ -1259,7 +1252,7 @@ private void ProcessControls() if (item == selectedItem && item is NativeSlidableItem slidable) { // If the right arrow was pressed, go to the right - if (Screen.IsCursorInArea(slidable.RightArrow.Position, slidable.RightArrow.Size)) + if (GameScreen.IsCursorInArea(slidable.RightArrow.Position, slidable.RightArrow.Size)) { if (item.Enabled) { @@ -1273,7 +1266,7 @@ private void ProcessControls() return; } // If the user pressed the left arrow, go to the right - else if (Screen.IsCursorInArea(slidable.LeftArrow.Position, slidable.LeftArrow.Size)) + else if (GameScreen.IsCursorInArea(slidable.LeftArrow.Position, slidable.LeftArrow.Size)) { if (item.Enabled) { @@ -1289,7 +1282,7 @@ private void ProcessControls() } // If the cursor is inside of the selection rectangle - if (Screen.IsCursorInArea(item.title.Position.X - itemOffsetX, item.title.Position.Y - itemOffsetY, Width, itemHeight)) + if (GameScreen.IsCursorInArea(item.title.Position.X - itemOffsetX, item.title.Position.Y - itemOffsetY, Width, itemHeight)) { // If the item is selected, activate it if (item == selectedItem) @@ -1688,9 +1681,8 @@ public virtual void Recalculate() x = Offset.X - Width; break; } - Screen.SetElementAlignment(Alignment, GFXAlignment.Top); - pos = Screen.GetRealPosition(x, Offset.Y); - Screen.ResetElementAlignment(); + + pos = SafeZone.GetPositionAt(new PointF(x, Offset.Y), Alignment, GFXAlignment.Top); } else { diff --git a/LemonUI/TimerBars/TimerBarCollection.cs b/LemonUI/TimerBars/TimerBarCollection.cs index e5b8810..cb7de5d 100644 --- a/LemonUI/TimerBars/TimerBarCollection.cs +++ b/LemonUI/TimerBars/TimerBarCollection.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using System.Drawing; using LemonUI.Elements; +using LemonUI.Tools; namespace LemonUI.TimerBars { @@ -139,9 +140,7 @@ public void Remove(Func func) /// public void Recalculate() { - Screen.SetElementAlignment(GFXAlignment.Right, GFXAlignment.Bottom); - PointF pos = Screen.GetRealPosition(PointF.Empty); - Screen.ResetElementAlignment(); + PointF pos = SafeZone.BottomRight; pos.X += offset.X; pos.Y += offset.Y; From d6e12af1fb46154568773d7db7ea539553e053a5 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:08:37 -0300 Subject: [PATCH 05/48] Renamed all of the Absolute references to Scaled The Absolute resolution is now the size of the game render window Fixes #144 --- LemonUI/Elements/ScaledText.cs | 20 ++++++------ LemonUI/Extensions/FloatExtensions.cs | 16 +++++----- LemonUI/Extensions/PointExtensions.cs | 10 +++--- LemonUI/Extensions/SizeExtensions.cs | 10 +++--- LemonUI/Menus/NativeMenu.cs | 8 ++--- LemonUI/Screen.cs | 4 +-- LemonUI/Tools/Extensions.cs | 44 +++++++++++++-------------- LemonUI/Tools/GameScreen.cs | 18 +++++------ LemonUI/Tools/SafeZone.cs | 6 ++-- 9 files changed, 68 insertions(+), 68 deletions(-) diff --git a/LemonUI/Elements/ScaledText.cs b/LemonUI/Elements/ScaledText.cs index 9c105a4..05fffb2 100644 --- a/LemonUI/Elements/ScaledText.cs +++ b/LemonUI/Elements/ScaledText.cs @@ -37,9 +37,9 @@ public class ScaledText : IText #region Fields /// - /// The absolute 1080p based screen position. + /// The scaled 1080p based screen position. /// - private PointF absolutePosition = PointF.Empty; + private PointF scaledPosition = PointF.Empty; /// /// The relative 0-1 relative position. /// @@ -74,10 +74,10 @@ public class ScaledText : IText /// public PointF Position { - get => absolutePosition; + get => scaledPosition; set { - absolutePosition = value; + scaledPosition = value; relativePosition = value.ToRelative(); } } @@ -150,23 +150,23 @@ public float Width #if FIVEM API.BeginTextCommandWidth("CELL_EMAIL_BCON"); Add(); - return API.EndTextCommandGetWidth(true) * 1f.ToXAbsolute(); + return API.EndTextCommandGetWidth(true) * 1f.ToXScaled(); #elif ALTV Alt.Natives.BeginTextCommandGetScreenWidthOfDisplayText("CELL_EMAIL_BCON"); Add(); - return Alt.Natives.EndTextCommandGetScreenWidthOfDisplayText(true) * 1f.ToXAbsolute(); + return Alt.Natives.EndTextCommandGetScreenWidthOfDisplayText(true) * 1f.ToXScaled(); #elif RAGEMP Invoker.Invoke(Natives.BeginTextCommandWidth, "CELL_EMAIL_BCON"); Add(); - return Invoker.Invoke(Natives.EndTextCommandGetWidth) * 1f.ToXAbsolute(); + return Invoker.Invoke(Natives.EndTextCommandGetWidth) * 1f.ToXScaled(); #elif RPH NativeFunction.CallByHash(0x54CE8AC98E120CAB, "CELL_EMAIL_BCON"); Add(); - return NativeFunction.CallByHash(0x85F061DA64ED2F67, true) * 1f.ToXAbsolute(); + return NativeFunction.CallByHash(0x85F061DA64ED2F67, true) * 1f.ToXScaled(); #elif SHVDN3 || SHVDNC Function.Call(Hash.BEGIN_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT, "CELL_EMAIL_BCON"); Add(); - return Function.Call(Hash.END_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT, true) * 1f.ToXAbsolute(); + return Function.Call(Hash.END_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT, true) * 1f.ToXScaled(); #endif } } @@ -505,7 +505,7 @@ private void Slice() public void Recalculate() { // Do the normal Size and Position recalculation - relativePosition = absolutePosition.ToRelative(); + relativePosition = scaledPosition.ToRelative(); // And recalculate the word wrap if necessary if (internalWrap <= 0) { diff --git a/LemonUI/Extensions/FloatExtensions.cs b/LemonUI/Extensions/FloatExtensions.cs index 0b82150..ddc7340 100644 --- a/LemonUI/Extensions/FloatExtensions.cs +++ b/LemonUI/Extensions/FloatExtensions.cs @@ -9,28 +9,28 @@ namespace LemonUI.Extensions public static class FloatExtensions { /// - /// Converts an absolute X or Width float to a relative one. + /// Converts a scaled X or Width float to a relative one. /// /// The float to convert. /// A relative float between 0 and 1. public static float ToXRelative(this float fin) => Tools.Extensions.ToXRelative(fin); /// - /// Converts an absolute Y or Height float to a relative one. + /// Converts a scaled Y or Height float to a relative one. /// /// The float to convert. /// A relative float between 0 and 1. public static float ToYRelative(this float fin) => Tools.Extensions.ToYRelative(fin); /// - /// Converts an relative X or Width float to an absolute one. + /// Converts an relative X or Width float to an scaled one. /// /// The float to convert. - /// An absolute float. - public static float ToXAbsolute(this float fin) => Tools.Extensions.ToXAbsolute(fin); + /// A scaled float. + public static float ToXAbsolute(this float fin) => Tools.Extensions.ToXScaled(fin); /// - /// Converts an relative Y or Height float to an absolute one. + /// Converts an relative Y or Height float to an scaled one. /// /// The float to convert. - /// An absolute float. - public static float ToYAbsolute(this float fin) => Tools.Extensions.ToYAbsolute(fin); + /// A scaled float. + public static float ToYAbsolute(this float fin) => Tools.Extensions.ToYScaled(fin); } } diff --git a/LemonUI/Extensions/PointExtensions.cs b/LemonUI/Extensions/PointExtensions.cs index 5d55083..5f0c267 100644 --- a/LemonUI/Extensions/PointExtensions.cs +++ b/LemonUI/Extensions/PointExtensions.cs @@ -10,16 +10,16 @@ namespace LemonUI.Extensions public static class PointExtensions { /// - /// Converts an absolute 1080-based position into a relative one. + /// Converts a scaled 1080-based position into a relative one. /// - /// The absolute PointF. + /// The scaled PointF. /// A new PointF with relative values. public static PointF ToRelative(this PointF point) => Tools.Extensions.ToRelative(point); /// - /// Converts a normalized 0-1 position into an absolute one. + /// Converts a normalized 0-1 position into a scaled one. /// /// The relative PointF. - /// A new PointF with absolute values. - public static PointF ToAbsolute(this PointF point) => Tools.Extensions.ToAbsolute(point); + /// A new PointF with scaled values. + public static PointF ToAbsolute(this PointF point) => Tools.Extensions.ToScaled(point); } } diff --git a/LemonUI/Extensions/SizeExtensions.cs b/LemonUI/Extensions/SizeExtensions.cs index 5d86e1e..0660a34 100644 --- a/LemonUI/Extensions/SizeExtensions.cs +++ b/LemonUI/Extensions/SizeExtensions.cs @@ -10,16 +10,16 @@ namespace LemonUI.Extensions public static class SizeExtensions { /// - /// Converts an absolute 1080-based size into a relative one. + /// Converts a scaled 1080-based size into a relative one. /// - /// The absolute SizeF. + /// The scaled SizeF. /// A new SizeF with relative values. public static SizeF ToRelative(this SizeF size) => Tools.Extensions.ToRelative(size); /// - /// Converts a normalized 0-1 size into an absolute one. + /// Converts a normalized 0-1 size into a scaled one. /// /// The relative SizeF. - /// A new SizeF with absolute values. - public static SizeF ToAbsolute(this SizeF size) => Tools.Extensions.ToAbsolute(size); + /// A new SizeF with scaled values. + public static SizeF ToAbsolute(this SizeF size) => Tools.Extensions.ToScaled(size); } } diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index 8a8edbb..c941294 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -976,7 +976,7 @@ public void ResetCursor() x = Offset.X + Width + extraX; break; case Alignment.Right: - x = 1f.ToXAbsolute() - Offset.X - Width - extraX; + x = 1f.ToXScaled() - Offset.X - Width - extraX; break; } pos = new PointF(x, Offset.Y + extraY).ToRelative(); @@ -1026,7 +1026,7 @@ private void UpdateItems() x = Offset.X; break; case Alignment.Right: - x = 1f.ToXAbsolute() - Width - Offset.X; + x = 1f.ToXScaled() - Width - Offset.X; break; } pos = new PointF(x, Offset.Y); @@ -1693,7 +1693,7 @@ public virtual void Recalculate() x = Offset.X; break; case Alignment.Right: - x = 1f.ToXAbsolute() - Width - Offset.X; + x = 1f.ToXScaled() - Width - Offset.X; break; } pos = new PointF(x, Offset.Y); @@ -1734,7 +1734,7 @@ public virtual void Recalculate() descriptionText.WordWrap = width - posXDescTxt; // Set the right size of the rotation - searchAreaRight = new PointF(1f.ToXAbsolute() - 30, 0); + searchAreaRight = new PointF(1f.ToXScaled() - 30, 0); // Then, continue with an item update UpdateItems(); diff --git a/LemonUI/Screen.cs b/LemonUI/Screen.cs index 52df2b2..639c260 100644 --- a/LemonUI/Screen.cs +++ b/LemonUI/Screen.cs @@ -67,8 +67,8 @@ public static Size Resolution /// The value of Y scaled to 1080p. public static void ToAbsolute(float relativeX, float relativeY, out float absoluteX, out float absoluteY) { - absoluteX = relativeX.ToXAbsolute(); - absoluteY = relativeY.ToYAbsolute(); + absoluteX = relativeX.ToXScaled(); + absoluteY = relativeY.ToYScaled(); } /// /// Converts a 1080p-based resolution into relative values. diff --git a/LemonUI/Tools/Extensions.cs b/LemonUI/Tools/Extensions.cs index 70461c0..d3f6556 100644 --- a/LemonUI/Tools/Extensions.cs +++ b/LemonUI/Tools/Extensions.cs @@ -3,70 +3,70 @@ namespace LemonUI.Tools { /// - /// Extensions for converting values between relative and absolute. + /// Extensions for converting values between relative and scaled. /// public static class Extensions { #region Float /// - /// Converts an absolute X or Width float to a relative one. + /// Converts the scaled X or Width to a relative one. /// - /// The float to convert. + /// The value to convert. /// A relative float between 0 and 1. public static float ToXRelative(this float x) => x / (1080f * GameScreen.AspectRatio); /// - /// Converts an absolute Y or Height float to a relative one. + /// Converts the scaled Y or Height to a relative one. /// - /// The float to convert. + /// The value to convert. /// A relative float between 0 and 1. public static float ToYRelative(this float y) => y / 1080f; /// - /// Converts an relative X or Width float to an absolute one. + /// Converts the relative X or Width float to a scaled one. /// /// The float to convert. - /// An absolute float. - public static float ToXAbsolute(this float x) => (1080f * GameScreen.AspectRatio) * x; + /// A scaled float. + public static float ToXScaled(this float x) => (1080f * GameScreen.AspectRatio) * x; /// - /// Converts an relative Y or Height float to an absolute one. + /// Converts the relative Y or Height float to a scaled one. /// /// The float to convert. - /// An absolute float. - public static float ToYAbsolute(this float y) => 1080f * y; + /// A scaled float. + public static float ToYScaled(this float y) => 1080f * y; #endregion #region PointF /// - /// Converts an absolute 1080-based position into a relative one. + /// Converts a scaled 1080p-based position into a relative one. /// - /// The absolute PointF. + /// The scaled PointF. /// A new PointF with relative values. public static PointF ToRelative(this PointF point) => new PointF(point.X.ToXRelative(), point.Y.ToYRelative()); /// - /// Converts a normalized 0-1 position into an absolute one. + /// Converts a relative 0-1 position into a scaled one. /// /// The relative PointF. - /// A new PointF with absolute values. - public static PointF ToAbsolute(this PointF point) => new PointF(point.X.ToXAbsolute(), point.Y.ToYAbsolute()); + /// A new PointF with scaled values. + public static PointF ToScaled(this PointF point) => new PointF(point.X.ToXScaled(), point.Y.ToYScaled()); #endregion #region SizeF /// - /// Converts an absolute 1080-based size into a relative one. + /// Converts a scaled 1080p-based position into a relative one. /// - /// The absolute SizeF. + /// The scaled SizeF. /// A new SizeF with relative values. - public static SizeF ToRelative(this SizeF size) => new SizeF(size.Width.ToXAbsolute(), size.Height.ToYAbsolute()); + public static SizeF ToRelative(this SizeF size) => new SizeF(size.Width.ToXScaled(), size.Height.ToYScaled()); /// - /// Converts a normalized 0-1 size into an absolute one. + /// Converts a relative 0-1 position into a scaled one. /// /// The relative SizeF. - /// A new SizeF with absolute values. - public static SizeF ToAbsolute(this SizeF size) => new SizeF(size.Width.ToXRelative(), size.Height.ToYRelative()); + /// A new SizeF with scaled values. + public static SizeF ToScaled(this SizeF size) => new SizeF(size.Width.ToXRelative(), size.Height.ToYRelative()); #endregion } diff --git a/LemonUI/Tools/GameScreen.cs b/LemonUI/Tools/GameScreen.cs index 5c15b6b..5556d59 100644 --- a/LemonUI/Tools/GameScreen.cs +++ b/LemonUI/Tools/GameScreen.cs @@ -69,7 +69,7 @@ public static PointF Cursor float cursorX = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorX); float cursorY = Function.Call(Hash.GET_CONTROL_NORMAL, 0, (int)Control.CursorY); #endif - return new PointF(cursorX.ToXAbsolute(), cursorY.ToYAbsolute()); + return new PointF(cursorX.ToXScaled(), cursorY.ToYScaled()); } } @@ -78,19 +78,19 @@ public static PointF Cursor #region Functions /// - /// Checks if the cursor is inside of the absolute area. + /// Checks if the cursor is inside of the scaled area. /// - /// The absolute position. - /// The absolute size of the area. + /// The scaled position. + /// The scaled size of the area. /// if the cursor is in the specified bounds, otherwise. public static bool IsCursorInArea(PointF pos, SizeF size) => IsCursorInArea(pos.X, pos.Y, size.Width, size.Height); /// - /// Checks if the cursor is inside of the absolute area. + /// Checks if the cursor is inside of the scaled area. /// - /// The absolute X position. - /// The absolute Y position. - /// The absolute width of the area. - /// The absolute height of the area. + /// The scaled X position. + /// The scaled Y position. + /// The scaled width of the area. + /// The scaled height of the area. /// if the cursor is in the specified bounds, otherwise. public static bool IsCursorInArea(float x, float y, float width, float height) { diff --git a/LemonUI/Tools/SafeZone.cs b/LemonUI/Tools/SafeZone.cs index a146eae..43be35b 100644 --- a/LemonUI/Tools/SafeZone.cs +++ b/LemonUI/Tools/SafeZone.cs @@ -109,7 +109,7 @@ public static PointF GetSafePosition(float x, float y) } #endif - return new PointF(realX.ToXAbsolute(), realY.ToYAbsolute()); + return new PointF(realX.ToXScaled(), realY.ToYScaled()); } /// /// Sets the alignment for the safe zone. @@ -164,7 +164,7 @@ public static void ResetAlignment() /// The position to get. /// The horizontal alignment. /// The vertical alignment. - /// The absolute safe zone alignment. + /// The safe zone alignment. public static PointF GetPositionAt(PointF position, Alignment horizontal, GFXAlignment vertical) => GetPositionAt(position, AlignmentToGFXAlignment(horizontal), vertical); /// /// Gets the specified position with the specified safe zone alignment. @@ -172,7 +172,7 @@ public static void ResetAlignment() /// The position to get. /// The horizontal alignment. /// The vertical alignment. - /// The absolute safe zone alignment. + /// The scaled safe zone alignment. public static PointF GetPositionAt(PointF position, GFXAlignment horizontal, GFXAlignment vertical) { SetAlignment(horizontal, vertical); From 74ee5d26230740c27d3acd54698347d1476c0b8c Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:19:43 -0300 Subject: [PATCH 06/48] Added property to get the absolute screen resolution Fixes #143 --- LemonUI/ObjectPool.cs | 27 +++------------------------ LemonUI/Screen.cs | 13 ++----------- LemonUI/Tools/GameScreen.cs | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/LemonUI/ObjectPool.cs b/LemonUI/ObjectPool.cs index 4405dd4..9935d25 100644 --- a/LemonUI/ObjectPool.cs +++ b/LemonUI/ObjectPool.cs @@ -15,6 +15,7 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; +using LemonUI.Tools; namespace LemonUI { @@ -28,17 +29,7 @@ public class ObjectPool : IEnumerable /// /// The last known resolution by the object pool. /// -#if FIVEM - private SizeF lastKnownResolution = CitizenFX.Core.UI.Screen.Resolution; -#elif ALTV - private SizeF lastKnownResolution = Screen.Resolution; -#elif RAGEMP - private SizeF lastKnownResolution = new SizeF(Game.ScreenResolution.Width, Game.ScreenResolution.Height); -#elif RPH - private SizeF lastKnownResolution = Game.Resolution; -#elif SHVDN3 || SHVDNC - private SizeF lastKnownResolution = GTA.UI.Screen.Resolution; -#endif + private SizeF lastKnownResolution = GameScreen.AbsoluteResolution; /// /// The last know Safezone size. /// @@ -53,7 +44,6 @@ public class ObjectPool : IEnumerable #elif SHVDN3 || SHVDNC private float lastKnownSafezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE); #endif - /// /// The list of processable objects. /// @@ -104,18 +94,7 @@ public bool AreAnyVisible private void DetectResolutionChanges() { // Get the current resolution -#if FIVEM - SizeF resolution = CitizenFX.Core.UI.Screen.Resolution; -#elif ALTV - SizeF resolution = Screen.Resolution; -#elif RAGEMP - ScreenResolutionType raw = Game.ScreenResolution; - SizeF resolution = new SizeF(raw.Width, raw.Height); -#elif RPH - SizeF resolution = Game.Resolution; -#elif SHVDN3 || SHVDNC - SizeF resolution = GTA.UI.Screen.Resolution; -#endif + SizeF resolution = GameScreen.AbsoluteResolution; // If the old res does not matches the current one if (lastKnownResolution != resolution) { diff --git a/LemonUI/Screen.cs b/LemonUI/Screen.cs index 639c260..b7c893d 100644 --- a/LemonUI/Screen.cs +++ b/LemonUI/Screen.cs @@ -34,20 +34,11 @@ public static class Screen /// The Aspect Ratio of the screen resolution. /// public static float AspectRatio => GameScreen.AspectRatio; - #if ALTV /// - /// Gets the actual Screen resolution the game is being rendered at + /// Gets the actual Screen resolution the game is being rendered at. /// - public static Size Resolution - { - get - { - int height = 0, width = 0; - Alt.Natives.GetActualScreenResolution(ref width, ref height); - return new Size(width, height); - } - } + public static Size Resolution => GameScreen.AbsoluteResolution.ToSize(); #endif /// /// The location of the cursor on screen between 0 and 1. diff --git a/LemonUI/Tools/GameScreen.cs b/LemonUI/Tools/GameScreen.cs index 5556d59..4315cf5 100644 --- a/LemonUI/Tools/GameScreen.cs +++ b/LemonUI/Tools/GameScreen.cs @@ -4,6 +4,7 @@ using CitizenFX.Core.UI; #elif RAGEMP using RAGE.Game; +using RAGE.NUI; #elif RPH using Rage; using Rage.Native; @@ -26,6 +27,29 @@ public static class GameScreen { #region Properties + /// + /// Gets the actual Screen resolution the game is being rendered at. + /// + public static SizeF AbsoluteResolution + { + get + { +#if ALTV + int height = 0, width = 0; + Alt.Natives.GetActualScreenResolution(ref width, ref height); + return new SizeF(width, height); +#elif FIVEM + return CitizenFX.Core.UI.Screen.Resolution; +#elif RAGEMP + ScreenResolutionType raw = Game.ScreenResolution; + return new SizeF(raw.Width, raw.Height); +#elif RPH + return Game.Resolution; +#elif SHVDN3 || SHVDNC + return GTA.UI.Screen.Resolution; +#endif + } + } /// /// The Aspect Ratio of the screen. /// From 62b65cd0e153a8f0fe2a094cb2668d6942ab2968 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:29:22 -0300 Subject: [PATCH 07/48] Added property to get the safe zone size Closes #146 --- LemonUI/ObjectPool.cs | 25 ++----------------------- LemonUI/Tools/SafeZone.cs | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/LemonUI/ObjectPool.cs b/LemonUI/ObjectPool.cs index 9935d25..cf4dbac 100644 --- a/LemonUI/ObjectPool.cs +++ b/LemonUI/ObjectPool.cs @@ -33,17 +33,7 @@ public class ObjectPool : IEnumerable /// /// The last know Safezone size. /// -#if FIVEM - private float lastKnownSafezone = API.GetSafeZoneSize(); -#elif ALTV - private float lastKnownSafezone = Alt.Natives.GetSafeZoneSize(); -#elif RAGEMP - private float lastKnownSafezone = Invoker.Invoke(Natives.GetSafeZoneSize); -#elif RPH - private float lastKnownSafezone = NativeFunction.CallByHash(0xBAF107B6BB2C97F0); -#elif SHVDN3 || SHVDNC - private float lastKnownSafezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE); -#endif + private float lastKnownSafezone = SafeZone.Size; /// /// The list of processable objects. /// @@ -112,18 +102,7 @@ private void DetectResolutionChanges() private void DetectSafezoneChanges() { // Get the current Safezone size -#if FIVEM - float safezone = API.GetSafeZoneSize(); -#elif ALTV - float safezone = Alt.Natives.GetSafeZoneSize(); -#elif RAGEMP - float safezone = Invoker.Invoke(Natives.GetSafeZoneSize); -#elif RPH - float safezone = NativeFunction.CallByHash(0xBAF107B6BB2C97F0); -#elif SHVDN3 || SHVDNC - float safezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE); -#endif - + float safezone = SafeZone.Size; // If is not the same as the last one if (lastKnownSafezone != safezone) { diff --git a/LemonUI/Tools/SafeZone.cs b/LemonUI/Tools/SafeZone.cs index 43be35b..4ddfa8d 100644 --- a/LemonUI/Tools/SafeZone.cs +++ b/LemonUI/Tools/SafeZone.cs @@ -23,6 +23,29 @@ public static class SafeZone { #region Properties + /// + /// The size of the safe zone. + /// + /// + /// This property should not be used to manually calculate the safe zone. Use to get the safe zone size. + /// + public static float Size + { + get + { +#if ALTV + return Alt.Natives.GetSafeZoneSize(); +#elif FIVEM + return API.GetSafeZoneSize(); +#elif RAGEMP + return Invoker.Invoke(Natives.GetSafeZoneSize); +#elif RPH + return NativeFunction.CallByHash(0xBAF107B6BB2C97F0); +#elif SHVDN3 || SHVDNC + return Function.Call(Hash.GET_SAFE_ZONE_SIZE); +#endif + } + } /// /// The top left corner after the safe zone. /// From 2b7bd9d4a8ce6b7b050a289a049f8fc6d318be01 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:41:22 -0300 Subject: [PATCH 08/48] Fixed Size ToRelative and ToScaled being swapped around --- LemonUI/Tools/Extensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LemonUI/Tools/Extensions.cs b/LemonUI/Tools/Extensions.cs index d3f6556..4d9c7e8 100644 --- a/LemonUI/Tools/Extensions.cs +++ b/LemonUI/Tools/Extensions.cs @@ -60,13 +60,13 @@ public static class Extensions /// /// The scaled SizeF. /// A new SizeF with relative values. - public static SizeF ToRelative(this SizeF size) => new SizeF(size.Width.ToXScaled(), size.Height.ToYScaled()); + public static SizeF ToRelative(this SizeF size) => new SizeF(size.Width.ToXRelative(), size.Height.ToYRelative()); /// /// Converts a relative 0-1 position into a scaled one. /// /// The relative SizeF. /// A new SizeF with scaled values. - public static SizeF ToScaled(this SizeF size) => new SizeF(size.Width.ToXRelative(), size.Height.ToYRelative()); + public static SizeF ToScaled(this SizeF size) => new SizeF(size.Width.ToXScaled(), size.Height.ToYScaled()); #endregion } From ee5a2a6ca8fa28ba3c3e010a96e40630b01a8f33 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:49:45 -0300 Subject: [PATCH 09/48] Don't do anything if there are no items Fixes #137 --- LemonUI/Menus/NativeListItem{T}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Menus/NativeListItem{T}.cs b/LemonUI/Menus/NativeListItem{T}.cs index ee2a11d..7c5d3b7 100644 --- a/LemonUI/Menus/NativeListItem{T}.cs +++ b/LemonUI/Menus/NativeListItem{T}.cs @@ -73,7 +73,7 @@ public T SelectedItem { if (Items.Count == 0) { - throw new InvalidOperationException("There are no available items."); + return; } int newIndex = Items.IndexOf(value); From 11e32cba2e30a2bf0734eb9a8d3b892b6deb889f Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 02:55:34 -0300 Subject: [PATCH 10/48] Added missing using statements --- LemonUI/Menus/NativeSpacerItem.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/LemonUI/Menus/NativeSpacerItem.cs b/LemonUI/Menus/NativeSpacerItem.cs index f017a4e..2c6b0ca 100644 --- a/LemonUI/Menus/NativeSpacerItem.cs +++ b/LemonUI/Menus/NativeSpacerItem.cs @@ -1,5 +1,11 @@ -using System.Drawing; +#if FIVEM +using CitizenFX.Core.UI; +#elif RAGEMP +using RAGE.Game; +#elif SHVDN3 || SHVDNC using GTA.UI; +#endif +using System.Drawing; namespace LemonUI.Menus { From 0eb4e55b077139d56f57c3bce4dc1471576278ba Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 03:19:25 -0300 Subject: [PATCH 11/48] Make NativeSeparatorItem obsolete Fixes #148 --- LemonUI/Menus/NativeSeparatorItem.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/LemonUI/Menus/NativeSeparatorItem.cs b/LemonUI/Menus/NativeSeparatorItem.cs index 2633e54..32a17db 100644 --- a/LemonUI/Menus/NativeSeparatorItem.cs +++ b/LemonUI/Menus/NativeSeparatorItem.cs @@ -1,8 +1,11 @@ -namespace LemonUI.Menus +using System; + +namespace LemonUI.Menus { /// /// A Blank Separator Item for creating empty spaces between menu items. /// + [Obsolete("Use LemonUI.Menus.NativeSpacerItem instead.", true)] public class NativeSeparatorItem : NativeItem { #region Constructors From 7ebc4c02599437b97ab7cda76c213ae248e4e262 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 03:25:50 -0300 Subject: [PATCH 12/48] Make sure that Spacers can't be clicked --- LemonUI/Menus/NativeItem.cs | 2 +- LemonUI/Menus/NativeMenu.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/LemonUI/Menus/NativeItem.cs b/LemonUI/Menus/NativeItem.cs index a36969b..9128523 100644 --- a/LemonUI/Menus/NativeItem.cs +++ b/LemonUI/Menus/NativeItem.cs @@ -393,7 +393,7 @@ public virtual void UpdateColors() badgeRight.Color = Colors.BadgeRightDisabled; } } - else if (lastSelected) + else if (lastSelected && !(this is NativeSpacerItem)) { background.Color = Colors.BackgroundHovered; title.Color = Colors.TitleHovered; diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index c941294..d4bc6ab 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -1284,6 +1284,11 @@ private void ProcessControls() // If the cursor is inside of the selection rectangle if (GameScreen.IsCursorInArea(item.title.Position.X - itemOffsetX, item.title.Position.Y - itemOffsetY, Width, itemHeight)) { + if (item is NativeSpacerItem) + { + return; + } + // If the item is selected, activate it if (item == selectedItem) { @@ -1426,7 +1431,7 @@ private void Draw() continue; } - if (item.IsHovered && UseMouse) + if (item.IsHovered && UseMouse && !(item is NativeSpacerItem)) { hoveredRect.Position = item.lastPosition; hoveredRect.Size = item.lastSize; From 2fa213db7834f6b11e87d220292cca137b6d7c7a Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 03:26:52 -0300 Subject: [PATCH 13/48] Make sure that we check that the items are actually hovered Fixes #147 --- LemonUI/Menus/NativeMenu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index d4bc6ab..479acc0 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -1282,7 +1282,7 @@ private void ProcessControls() } // If the cursor is inside of the selection rectangle - if (GameScreen.IsCursorInArea(item.title.Position.X - itemOffsetX, item.title.Position.Y - itemOffsetY, Width, itemHeight)) + if (item.IsHovered) { if (item is NativeSpacerItem) { From 436cfcadb522010fd34414bfea20ea44da06e8e9 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 03:36:55 -0300 Subject: [PATCH 14/48] Revert "Make NativeSeparatorItem obsolete" This reverts commit 0eb4e55b077139d56f57c3bce4dc1471576278ba. --- LemonUI/Menus/NativeSeparatorItem.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/LemonUI/Menus/NativeSeparatorItem.cs b/LemonUI/Menus/NativeSeparatorItem.cs index 32a17db..2633e54 100644 --- a/LemonUI/Menus/NativeSeparatorItem.cs +++ b/LemonUI/Menus/NativeSeparatorItem.cs @@ -1,11 +1,8 @@ -using System; - -namespace LemonUI.Menus +namespace LemonUI.Menus { /// /// A Blank Separator Item for creating empty spaces between menu items. /// - [Obsolete("Use LemonUI.Menus.NativeSpacerItem instead.", true)] public class NativeSeparatorItem : NativeItem { #region Constructors From 905155365e80673ce9cc38a32836b57115cd6f91 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 03:43:09 -0300 Subject: [PATCH 15/48] Merge the features of NativeSpacerItem into NativeSeparatorItem --- LemonUI/Menus/NativeItem.cs | 2 +- LemonUI/Menus/NativeMenu.cs | 66 +++++++++++++++++++--------- LemonUI/Menus/NativeSeparatorItem.cs | 37 +++++++++++++--- LemonUI/Menus/NativeSpacerItem.cs | 53 ---------------------- 4 files changed, 77 insertions(+), 81 deletions(-) delete mode 100644 LemonUI/Menus/NativeSpacerItem.cs diff --git a/LemonUI/Menus/NativeItem.cs b/LemonUI/Menus/NativeItem.cs index 9128523..9bbbd7c 100644 --- a/LemonUI/Menus/NativeItem.cs +++ b/LemonUI/Menus/NativeItem.cs @@ -393,7 +393,7 @@ public virtual void UpdateColors() badgeRight.Color = Colors.BadgeRightDisabled; } } - else if (lastSelected && !(this is NativeSpacerItem)) + else if (lastSelected && !(this is NativeSeparatorItem)) { background.Color = Colors.BackgroundHovered; title.Color = Colors.TitleHovered; diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index 479acc0..758480d 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -1284,7 +1284,7 @@ private void ProcessControls() // If the cursor is inside of the selection rectangle if (item.IsHovered) { - if (item is NativeSpacerItem) + if (item is NativeSeparatorItem) { return; } @@ -1431,7 +1431,7 @@ private void Draw() continue; } - if (item.IsHovered && UseMouse && !(item is NativeSpacerItem)) + if (item.IsHovered && UseMouse && !(item is NativeSeparatorItem)) { hoveredRect.Position = item.lastPosition; hoveredRect.Size = item.lastSize; @@ -1779,21 +1779,34 @@ public void Back() /// public void Previous() { - // If there are no items, return if (Items.Count == 0) { return; } - // If we are on the first item, go back to the last one - if (SelectedIndex <= 0) - { - SelectedIndex = Items.Count - 1; - } - // Otherwise, reduce it by one - else + int nextIndex = SelectedIndex; + + while (true) { - SelectedIndex -= 1; + nextIndex -= 1; + + if (nextIndex < 0) + { + nextIndex = Items.Count - 1; + } + + if (Items[nextIndex] is NativeSeparatorItem) + { + continue; + } + + if (nextIndex == SelectedIndex) + { + return; + } + + SelectedIndex = nextIndex; + return; } } /// @@ -1802,21 +1815,34 @@ public void Previous() /// public void Next() { - // If there are no items, return if (Items.Count == 0) { return; } - // If we are on the last item, go back to the first one - if (Items.Count - 1 == SelectedIndex) - { - SelectedIndex = 0; - } - // Otherwise, increase it by one - else + int nextIndex = SelectedIndex; + + while (true) { - SelectedIndex += 1; + nextIndex += 1; + + if (nextIndex >= Items.Count) + { + nextIndex = 0; + } + + if (Items[nextIndex] is NativeSeparatorItem) + { + continue; + } + + if (nextIndex == SelectedIndex) + { + return; + } + + SelectedIndex = nextIndex; + return; } } diff --git a/LemonUI/Menus/NativeSeparatorItem.cs b/LemonUI/Menus/NativeSeparatorItem.cs index 2633e54..0e9526a 100644 --- a/LemonUI/Menus/NativeSeparatorItem.cs +++ b/LemonUI/Menus/NativeSeparatorItem.cs @@ -1,28 +1,51 @@ -namespace LemonUI.Menus +#if FIVEM +using CitizenFX.Core.UI; +#elif RAGEMP +using RAGE.Game; +#elif SHVDN3 || SHVDNC +using GTA.UI; +#endif +using System.Drawing; + +namespace LemonUI.Menus { /// - /// A Blank Separator Item for creating empty spaces between menu items. + /// An item used to have a space between the items with text or no text. /// public class NativeSeparatorItem : NativeItem { #region Constructors /// - /// Creates a new Menu Separator. + /// Creates a new separator. + /// + public NativeSeparatorItem() : this(string.Empty) + { + } + /// + /// Creates a new separator with a specific title. /// - public NativeSeparatorItem() : base(string.Empty, string.Empty, string.Empty) + /// The title of the item. + public NativeSeparatorItem(string title) : base(title, string.Empty, string.Empty) { + this.title.Alignment = Alignment.Center; } #endregion #region Functions - /// - /// Draws nothing. - /// + /// + public override void Recalculate(PointF pos, SizeF size, bool selected) + { + base.Recalculate(pos, size, selected); + + title.Position = new PointF(pos.X + (size.Width * 0.5f), title.Position.Y); + } + /// public override void Draw() { + title.Draw(); } #endregion diff --git a/LemonUI/Menus/NativeSpacerItem.cs b/LemonUI/Menus/NativeSpacerItem.cs deleted file mode 100644 index 2c6b0ca..0000000 --- a/LemonUI/Menus/NativeSpacerItem.cs +++ /dev/null @@ -1,53 +0,0 @@ -#if FIVEM -using CitizenFX.Core.UI; -#elif RAGEMP -using RAGE.Game; -#elif SHVDN3 || SHVDNC -using GTA.UI; -#endif -using System.Drawing; - -namespace LemonUI.Menus -{ - /// - /// An item used to have a space between the items with text. - /// - public class NativeSpacerItem : NativeItem - { - #region Constructor - - /// - /// Creates a new Spacer with no text. - /// - public NativeSpacerItem() : this(string.Empty) - { - } - /// - /// Creates a new Spacer with a specific title. - /// - /// The title of the item. - public NativeSpacerItem(string title) : base(title, string.Empty, string.Empty) - { - this.title.Alignment = Alignment.Center; - } - - #endregion - - #region Function - - /// - public override void Recalculate(PointF pos, SizeF size, bool selected) - { - base.Recalculate(pos, size, selected); - - title.Position = new PointF(pos.X + (size.Width * 0.5f), title.Position.Y); - } - /// - public override void Draw() - { - title.Draw(); - } - - #endregion - } -} From 7af5a31d03b2d2a96e7d5d2a6d4b59c896211b3d Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 04:04:57 -0300 Subject: [PATCH 16/48] Make sure that parameters and constructors don't accept null Fixes #123 --- LemonUI/Elements/ScaledText.cs | 7 ++-- LemonUI/Menus/BadgeSet.cs | 51 +++++++++++++++++++++++------- LemonUI/Menus/NativeColorData.cs | 12 +++++-- LemonUI/Menus/NativeColorPanel.cs | 16 ++-------- LemonUI/Menus/NativeGridPanel.cs | 8 ++--- LemonUI/Menus/NativeItem.cs | 11 +++++-- LemonUI/Menus/NativeMenu.cs | 2 +- LemonUI/Menus/NativeStatsInfo.cs | 4 +-- LemonUI/Menus/NativeSubmenuItem.cs | 4 +-- LemonUI/Sound.cs | 24 +++++++++++--- 10 files changed, 91 insertions(+), 48 deletions(-) diff --git a/LemonUI/Elements/ScaledText.cs b/LemonUI/Elements/ScaledText.cs index 05fffb2..9da274f 100644 --- a/LemonUI/Elements/ScaledText.cs +++ b/LemonUI/Elements/ScaledText.cs @@ -13,6 +13,7 @@ using GTA.UI; using Font = GTA.UI.Font; #endif +using System; using System.Collections.Generic; using System.Drawing; using System.Text; @@ -89,7 +90,7 @@ public string Text get => text; set { - text = value; + text = value ?? throw new ArgumentNullException(nameof(value)); Slice(); } } @@ -236,7 +237,6 @@ public float LineHeight public ScaledText(PointF pos, string text) : this(pos, text, 1f, Font.ChaletLondon) { } - /// /// Creates a text with the specified options. /// @@ -246,7 +246,6 @@ public ScaledText(PointF pos, string text) : this(pos, text, 1f, Font.ChaletLond public ScaledText(PointF pos, string text, float scale) : this(pos, text, scale, Font.ChaletLondon) { } - /// /// Creates a text with the specified options /// @@ -257,7 +256,7 @@ public ScaledText(PointF pos, string text, float scale) : this(pos, text, scale, public ScaledText(PointF pos, string text, float scale, Font font) { Position = pos; - Text = text; + Text = text ?? throw new ArgumentNullException(nameof(text)); Scale = scale; Font = font; } diff --git a/LemonUI/Menus/BadgeSet.cs b/LemonUI/Menus/BadgeSet.cs index 5566f4a..e0fb2d5 100644 --- a/LemonUI/Menus/BadgeSet.cs +++ b/LemonUI/Menus/BadgeSet.cs @@ -1,3 +1,5 @@ +using System; + namespace LemonUI.Menus { /// @@ -5,24 +7,49 @@ namespace LemonUI.Menus /// public class BadgeSet { + #region Fields + + private string normalDict = string.Empty; + private string normalTexture = string.Empty; + private string hoveredDict = string.Empty; + private string hoveredTexture = string.Empty; + + #endregion + #region Properties /// /// The texture dictionary where the normal texture is located. /// - public string NormalDictionary { get; set; } = string.Empty; + public string NormalDictionary + { + get => normalDict; + set => normalDict = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The texture to use when the item is not hovered. /// - public string NormalTexture { get; set; } = string.Empty; + public string NormalTexture + { + get => normalTexture; + set => normalTexture = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The texture dictionary where the normal texture is located. /// - public string HoveredDictionary { get; set; } = string.Empty; + public string HoveredDictionary + { + get => hoveredDict; + set => hoveredDict = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The texture to use when the item is hovered. /// - public string HoveredTexture { get; set; } = string.Empty; + public string HoveredTexture + { + get => hoveredTexture; + set => hoveredTexture = value ?? throw new ArgumentNullException(nameof(value)); + } #endregion @@ -42,10 +69,10 @@ public BadgeSet() /// The hovered texture name. public BadgeSet(string dict, string normal, string hovered) { - NormalDictionary = dict; - NormalTexture = normal; - HoveredDictionary = dict; - HoveredTexture = hovered; + normalDict = dict ?? throw new ArgumentNullException(nameof(dict)); + normalTexture = normal ?? throw new ArgumentNullException(nameof(normal)); + hoveredDict = dict; + hoveredTexture = hovered ?? throw new ArgumentNullException(nameof(hovered)); } /// /// Creates a new where both textures are in different dictionaries. @@ -56,10 +83,10 @@ public BadgeSet(string dict, string normal, string hovered) /// The hovered texture name. public BadgeSet(string normalDict, string normalTexture, string hoveredDict, string hoveredTexture) { - NormalDictionary = normalDict; - NormalTexture = normalTexture; - HoveredDictionary = hoveredDict; - HoveredTexture = hoveredTexture; + this.normalDict = normalDict ?? throw new ArgumentNullException(nameof(normalDict)); + this.normalTexture = normalTexture ?? throw new ArgumentNullException(nameof(normalTexture)); + this.hoveredDict = hoveredDict ?? throw new ArgumentNullException(nameof(hoveredDict)); + this.hoveredTexture = hoveredTexture ?? throw new ArgumentNullException(nameof(hoveredTexture)); } #endregion diff --git a/LemonUI/Menus/NativeColorData.cs b/LemonUI/Menus/NativeColorData.cs index d032135..53f3698 100644 --- a/LemonUI/Menus/NativeColorData.cs +++ b/LemonUI/Menus/NativeColorData.cs @@ -1,4 +1,5 @@ -using System.Drawing; +using System; +using System.Drawing; using LemonUI.Elements; namespace LemonUI.Menus @@ -10,6 +11,7 @@ public class NativeColorData { #region Fields + private string name = string.Empty; internal readonly ScaledRectangle rectangle = new ScaledRectangle(PointF.Empty, SizeF.Empty); #endregion @@ -19,7 +21,11 @@ public class NativeColorData /// /// The name of the color. /// - public string Name { get; set; } + public string Name + { + get => name; + set => name = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The RGBA values of the color. /// @@ -40,7 +46,7 @@ public Color Color /// The RGBA values of the color. public NativeColorData(string name, Color color) { - Name = name; + this.name = name ?? throw new ArgumentNullException(nameof(name)); rectangle.Color = color; } diff --git a/LemonUI/Menus/NativeColorPanel.cs b/LemonUI/Menus/NativeColorPanel.cs index 5991fbf..0044cc5 100644 --- a/LemonUI/Menus/NativeColorPanel.cs +++ b/LemonUI/Menus/NativeColorPanel.cs @@ -24,7 +24,6 @@ namespace LemonUI.Menus /// public class NativeColorPanel : NativePanel, IEnumerable { - #region Constants /// @@ -310,7 +309,6 @@ public int SelectedIndex Sound?.PlayFrontend(); } } - /// /// The Title used for the Panel when is set to . /// @@ -319,11 +317,10 @@ public string Title get => simpleTitle; set { - simpleTitle = value; + simpleTitle = value ?? throw new ArgumentNullException(nameof(value)); UpdateTitle(); } } - /// /// The style of the Panel Title. /// @@ -336,7 +333,6 @@ public ColorTitleStyle TitleStyle UpdateTitle(); } } - /// /// If the count of items should be shown as part of the title. /// @@ -349,7 +345,6 @@ public bool ShowCount UpdateTitle(); } } - /// /// THe maximum number of items shown on the screen. /// @@ -368,7 +363,6 @@ public int MaxItems UpdateTitle(); } } - /// /// The colors shown on this Panel. /// @@ -388,7 +382,6 @@ public int MaxItems public NativeColorPanel() : this(string.Empty) { } - /// /// Creates a Panel with a specific Title and set of Colors. /// @@ -396,9 +389,7 @@ public NativeColorPanel() : this(string.Empty) /// The colors of the panel. public NativeColorPanel(string title, params NativeColorData[] colors) { - // Set the title of the Panel - Title = title; - // Add the colors that we got + Title = title ?? throw new ArgumentNullException(nameof(title)); Colors.AddRange(colors); } @@ -422,7 +413,6 @@ private void UpdateTitle() break; case ColorTitleStyle.ColorName: newTitle = SelectedItem == null ? string.Empty : SelectedItem.Name; - break; } @@ -756,4 +746,4 @@ public override void Process() #endregion } -} \ No newline at end of file +} diff --git a/LemonUI/Menus/NativeGridPanel.cs b/LemonUI/Menus/NativeGridPanel.cs index afc3a78..8b88464 100644 --- a/LemonUI/Menus/NativeGridPanel.cs +++ b/LemonUI/Menus/NativeGridPanel.cs @@ -136,7 +136,7 @@ public float Y public string LabelTop { get => labelTop.Text; - set => labelTop.Text = value; + set => labelTop.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The text label shown on the bottom. @@ -144,7 +144,7 @@ public string LabelTop public string LabelBottom { get => labelBottom.Text; - set => labelBottom.Text = value; + set => labelBottom.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The text label shown on the left. @@ -152,7 +152,7 @@ public string LabelBottom public string LabelLeft { get => labelLeft.Text; - set => labelLeft.Text = value; + set => labelLeft.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The text label shown on the right. @@ -160,7 +160,7 @@ public string LabelLeft public string LabelRight { get => labelRight.Text; - set => labelRight.Text = value; + set => labelRight.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The style of this grid. diff --git a/LemonUI/Menus/NativeItem.cs b/LemonUI/Menus/NativeItem.cs index 9bbbd7c..3d3b6d4 100644 --- a/LemonUI/Menus/NativeItem.cs +++ b/LemonUI/Menus/NativeItem.cs @@ -56,6 +56,7 @@ public class NativeItem : IDrawable private BadgeSet badgeSetRight; private ColorSet colors = new ColorSet(); private ScaledRectangle background = new ScaledRectangle(PointF.Empty, SizeF.Empty); + private string description = string.Empty; #endregion @@ -88,7 +89,7 @@ public bool Enabled public string Title { get => title.Text; - set => title.Text = value; + set => title.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The alternative title of the item shown on the right. @@ -98,7 +99,7 @@ public string AltTitle get => altTitle.Text; set { - altTitle.Text = value; + altTitle.Text = value ?? throw new ArgumentNullException(nameof(value)); Recalculate(); } } @@ -121,7 +122,11 @@ public Font AltTitleFont /// /// The description of the item. /// - public string Description { get; set; } + public string Description + { + get => description; + set => description = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The Left badge of the Item. /// diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index 758480d..e61d1d9 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -520,7 +520,7 @@ public string Name get => name; set { - name = value; + name = value ?? throw new ArgumentNullException(nameof(value)); nameText.Text = value.ToUpperInvariant(); } } diff --git a/LemonUI/Menus/NativeStatsInfo.cs b/LemonUI/Menus/NativeStatsInfo.cs index a187bb8..72b8cff 100644 --- a/LemonUI/Menus/NativeStatsInfo.cs +++ b/LemonUI/Menus/NativeStatsInfo.cs @@ -29,7 +29,7 @@ public class NativeStatsInfo public string Name { get => text.Text; - set => text.Text = value; + set => text.Text = value ?? throw new ArgumentNullException(nameof(value)); } /// /// The value of the Stats bar. @@ -67,7 +67,7 @@ public NativeStatsInfo(string name) : this(name, 0) /// public NativeStatsInfo(string name, int value) { - Name = name; + Name = name ?? throw new ArgumentNullException(nameof(name)); this.value = value; for (int i = 0; i < 5; i++) diff --git a/LemonUI/Menus/NativeSubmenuItem.cs b/LemonUI/Menus/NativeSubmenuItem.cs index 62ab6a6..940ae08 100644 --- a/LemonUI/Menus/NativeSubmenuItem.cs +++ b/LemonUI/Menus/NativeSubmenuItem.cs @@ -31,8 +31,8 @@ public NativeSubmenuItem(NativeMenu menu, NativeMenu parent) : this(menu, parent /// /// The menu that this item will open. /// The parent menu where this item will be located. - /// The alternative title of the item, shown on the right. - public NativeSubmenuItem(NativeMenu menu, NativeMenu parent, string endlabel) : base(menu.Name, menu.Description, endlabel) + /// The alternative title of the item, shown on the right. + public NativeSubmenuItem(NativeMenu menu, NativeMenu parent, string endLabel) : base(menu.Name, menu.Description, endLabel) { Menu = menu ?? throw new ArgumentNullException(nameof(menu)); Menu.Parent = parent ?? throw new ArgumentNullException(nameof(parent)); diff --git a/LemonUI/Sound.cs b/LemonUI/Sound.cs index 54c0ab0..99459cb 100644 --- a/LemonUI/Sound.cs +++ b/LemonUI/Sound.cs @@ -7,6 +7,7 @@ using Rage; using Rage.Native; #elif SHVDN3 || SHVDNC +using System; using GTA; using GTA.Native; #elif ALTV @@ -21,6 +22,13 @@ namespace LemonUI /// public class Sound { + #region Fields + + private string set = string.Empty; + private string file = string.Empty; + + #endregion + #region Properties /// @@ -30,11 +38,19 @@ public class Sound /// /// The Set where the sound is located. /// - public string Set { get; set; } + public string Set + { + get => set; + set => set = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// The name of the sound file. /// - public string File { get; set; } + public string File + { + get => file; + set => file = value ?? throw new ArgumentNullException(nameof(value)); + } #endregion @@ -47,8 +63,8 @@ public class Sound /// The name of the sound file. public Sound(string set, string file) { - Set = set; - File = file; + Set = set ?? throw new ArgumentNullException(nameof(set)); + File = file ?? throw new ArgumentNullException(nameof(file)); } #endregion From 77dc787c4baa17859534639df8c823de46ae089c Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 04:30:22 -0300 Subject: [PATCH 17/48] Added basics of the Bink Video class --- LemonUI/Elements/ScaledBink.cs | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 LemonUI/Elements/ScaledBink.cs diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs new file mode 100644 index 0000000..9e723f9 --- /dev/null +++ b/LemonUI/Elements/ScaledBink.cs @@ -0,0 +1,67 @@ +#if ALTV +using AltV.Net.Client; +#elif FIVEM +using CitizenFX.Core.Native; +#elif RAGEMP +using RAGE.Game; +#elif RPH +using Rage.Native; +#elif SHVDN3 || SHVDNC +using GTA.Native; +#endif +using System; +using System.Drawing; + +namespace LemonUI.Elements +{ + /// + /// A Bink Video file. + /// + public class ScaledBink : BaseElement + { + #region Fields + + private string name = string.Empty; + private int id = 0; + + #endregion + + #region Constructors + + /// + /// Creates a new Bink Video playback. + /// + /// The name of the bik file. + /// The position of the video window. + /// The size of the video window. + public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) + { + this.name = name ?? throw new ArgumentNullException(nameof(name)); + +#if ALTV + id = Alt.Natives.SetBinkMovie(name); +#elif FIVEM + id = API.SetBinkMovie(name); +#elif RAGEMP + id = Invoker.Invoke(0xfc36643f7a64338f, name); +#elif RPH + id = NativeFunction.CallByHash(0xfc36643f7a64338f, name); +#elif SHVDN3 || SHVDNC + id = Function.Call(Hash.SET_BINK_MOVIE, name); +#endif + } + + #endregion + + #region Functions + + /// + /// Draws the Bink Movie at the specified location. + /// + public override void Draw() + { + } + + #endregion + } +} From 667969473cbdd555abc81a70f045139daf132666 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 11:39:40 -0300 Subject: [PATCH 18/48] Fixed location of the System import --- LemonUI/Sound.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Sound.cs b/LemonUI/Sound.cs index 99459cb..7d278d3 100644 --- a/LemonUI/Sound.cs +++ b/LemonUI/Sound.cs @@ -7,13 +7,13 @@ using Rage; using Rage.Native; #elif SHVDN3 || SHVDNC -using System; using GTA; using GTA.Native; #elif ALTV using AltV.Net.Client; using AltV.Net.Client.Elements.Entities; #endif +using System; namespace LemonUI { From 48e4a6119beea03f0a6f4946f6df370c650a64f5 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 15:42:25 -0300 Subject: [PATCH 19/48] Added extra constructor to skip the position and size --- LemonUI/Elements/ScaledBink.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 9e723f9..22cd4df 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -28,6 +28,13 @@ public class ScaledBink : BaseElement #region Constructors + /// + /// Creates a new Bink Video playback. + /// + /// The name of the bik file. + public ScaledBink(string name) : this(name, PointF.Empty, SizeF.Empty) + { + } /// /// Creates a new Bink Video playback. /// From c19b372ac00b4a6ac845b9f992060298dfaa62bb Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 15:43:15 -0300 Subject: [PATCH 20/48] Make sure to properly calculate the position from the center --- LemonUI/Elements/ScaledBink.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 22cd4df..6aed18e 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -68,6 +68,13 @@ public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) public override void Draw() { } + /// + public override void Recalculate() + { + base.Recalculate(); + relativePosition.X += relativeSize.Width * 0.5f; + relativePosition.Y += relativeSize.Height * 0.5f; + } #endregion } From 392957c7496447be4e2e9b50749af0ad42dfd863 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 15:43:27 -0300 Subject: [PATCH 21/48] Added drawing calls for Bink --- LemonUI/Elements/ScaledBink.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 6aed18e..b25a111 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -67,6 +67,22 @@ public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) /// public override void Draw() { +#if ALTV + Alt.Natives.PlayBinkMovie(id); + Alt.Natives.DrawBinkMovie(id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#elif FIVEM + API.PlayBinkMovie(id); + API.DrawBinkMovie(id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#elif RAGEMP + Invoker.Invoke(0xE178310643033958, id); + Invoker.Invoke(0x7118E83EEB9F7238, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#elif RPH + NativeFunction.CallByHash(0xE178310643033958, id); + NativeFunction.CallByHash(0x7118E83EEB9F7238, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.PLAY_BINK_MOVIE, id); + Function.Call(Hash.DRAW_BINK_MOVIE, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#endif } /// public override void Recalculate() From 9467f7e67e95b51291018de4bf13cf1a03b85594 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 15:45:23 -0300 Subject: [PATCH 22/48] Added extra constructor to skip the position of the bink video --- LemonUI/Elements/ScaledBink.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index b25a111..dfd2570 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -39,6 +39,14 @@ public ScaledBink(string name) : this(name, PointF.Empty, SizeF.Empty) /// Creates a new Bink Video playback. /// /// The name of the bik file. + /// The size of the video window. + public ScaledBink(string name, SizeF size) : this(name, PointF.Empty, size) + { + } + /// + /// Creates a new Bink Video playback. + /// + /// The name of the bik file. /// The position of the video window. /// The size of the video window. public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) From 87e790472ef82f911947b245cff57545c3f225f9 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 15:55:04 -0300 Subject: [PATCH 23/48] Moved Bink Movie name to a property --- LemonUI/Elements/ScaledBink.cs | 42 +++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index dfd2570..0a1fabd 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -26,6 +26,34 @@ public class ScaledBink : BaseElement #endregion + #region Properties + + /// + /// The name of the Bink Video file. + /// + public string Name + { + get => name; + set + { + name = value ?? throw new ArgumentNullException(nameof(value)); + +#if ALTV + id = Alt.Natives.SetBinkMovie(name); +#elif FIVEM + id = API.SetBinkMovie(name); +#elif RAGEMP + id = Invoker.Invoke(0xfc36643f7a64338f, name); +#elif RPH + id = NativeFunction.CallByHash(0xfc36643f7a64338f, name); +#elif SHVDN3 || SHVDNC + id = Function.Call(Hash.SET_BINK_MOVIE, name); +#endif + } + } + + #endregion + #region Constructors /// @@ -51,19 +79,7 @@ public ScaledBink(string name, SizeF size) : this(name, PointF.Empty, size) /// The size of the video window. public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) { - this.name = name ?? throw new ArgumentNullException(nameof(name)); - -#if ALTV - id = Alt.Natives.SetBinkMovie(name); -#elif FIVEM - id = API.SetBinkMovie(name); -#elif RAGEMP - id = Invoker.Invoke(0xfc36643f7a64338f, name); -#elif RPH - id = NativeFunction.CallByHash(0xfc36643f7a64338f, name); -#elif SHVDN3 || SHVDNC - id = Function.Call(Hash.SET_BINK_MOVIE, name); -#endif + Name = name ?? throw new ArgumentNullException(nameof(name)); } #endregion From 70b73a5ac99b032ed63022cff6dc49f28f775a02 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 16:26:06 -0300 Subject: [PATCH 24/48] Adedd function to stop a Bink Video --- LemonUI/Elements/ScaledBink.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 0a1fabd..e33a0d6 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -106,6 +106,26 @@ public override void Draw() #elif SHVDN3 || SHVDNC Function.Call(Hash.PLAY_BINK_MOVIE, id); Function.Call(Hash.DRAW_BINK_MOVIE, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); +#endif + } + /// + /// Stops the playback of the Bink Video. + /// + /// + /// If is called after this function. playback will start again. + /// + public void Stop() + { +#if ALTV + Alt.Natives.StopBinkMovie(id); +#elif FIVEM + API.StopBinkMovie(id); +#elif RAGEMP + Invoker.Invoke(0x63606A61DE68898A, id); +#elif RPH + NativeFunction.CallByHash(0x63606A61DE68898A, id); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.STOP_BINK_MOVIE, id); #endif } /// From 46283008330e62cf15c723fb4a47e0949ce6019f Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 16:34:52 -0300 Subject: [PATCH 25/48] Make the bink video id disposable --- LemonUI/Elements/ScaledBink.cs | 36 +++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index e33a0d6..23df25a 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -17,7 +17,7 @@ namespace LemonUI.Elements /// /// A Bink Video file. /// - public class ScaledBink : BaseElement + public class ScaledBink : BaseElement, IDisposable { #region Fields @@ -91,6 +91,11 @@ public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) /// public override void Draw() { + if (id == -1) + { + return; + } + #if ALTV Alt.Natives.PlayBinkMovie(id); Alt.Natives.DrawBinkMovie(id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); @@ -116,6 +121,11 @@ public override void Draw() /// public void Stop() { + if (id == -1) + { + return; + } + #if ALTV Alt.Natives.StopBinkMovie(id); #elif FIVEM @@ -128,6 +138,30 @@ public void Stop() Function.Call(Hash.STOP_BINK_MOVIE, id); #endif } + /// + /// Disposes the Bink Video ID. + /// + public void Dispose() + { + if (id == -1) + { + return; + } + +#if ALTV + Alt.Natives.ReleaseBinkMovie(id); +#elif FIVEM + API.ReleaseBinkMovie(id); +#elif RAGEMP + Invoker.Invoke(0x04D950EEFA4EED8C, id); +#elif RPH + NativeFunction.CallByHash(0x04D950EEFA4EED8C, id); +#elif SHVDN3 || SHVDNC + Function.Call(Hash.RELEASE_BINK_MOVIE, id); +#endif + + id = -1; + } /// public override void Recalculate() { From e6402e2c2a04a991cdb347c21e51ff2daa6037c7 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 16:35:21 -0300 Subject: [PATCH 26/48] Added finalizer so the bink video id gets released --- LemonUI/Elements/ScaledBink.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 23df25a..6afb078 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -84,6 +84,15 @@ public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) #endregion + #region Finalizer + + /// + /// Finalizes an instance of the class. + /// + ~ScaledBink() => Dispose(); + + #endregion + #region Functions /// From 05eece6d0b76794fc584cfe61a0cbb92a9f56c74 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 21:20:17 -0300 Subject: [PATCH 27/48] Make the Bink ID a property --- LemonUI/Elements/ScaledBink.cs | 63 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/LemonUI/Elements/ScaledBink.cs b/LemonUI/Elements/ScaledBink.cs index 6afb078..6a27a6a 100644 --- a/LemonUI/Elements/ScaledBink.cs +++ b/LemonUI/Elements/ScaledBink.cs @@ -22,12 +22,15 @@ public class ScaledBink : BaseElement, IDisposable #region Fields private string name = string.Empty; - private int id = 0; #endregion #region Properties + /// + /// The ID of the Bink Video Instance. + /// + public int Id { get; private set; } = -1; /// /// The name of the Bink Video file. /// @@ -39,15 +42,15 @@ public string Name name = value ?? throw new ArgumentNullException(nameof(value)); #if ALTV - id = Alt.Natives.SetBinkMovie(name); + Id = Alt.Natives.SetBinkMovie(name); #elif FIVEM - id = API.SetBinkMovie(name); + Id = API.SetBinkMovie(name); #elif RAGEMP - id = Invoker.Invoke(0xfc36643f7a64338f, name); + Id = Invoker.Invoke(0xfc36643f7a64338f, name); #elif RPH - id = NativeFunction.CallByHash(0xfc36643f7a64338f, name); + Id = NativeFunction.CallByHash(0xfc36643f7a64338f, name); #elif SHVDN3 || SHVDNC - id = Function.Call(Hash.SET_BINK_MOVIE, name); + Id = Function.Call(Hash.SET_BINK_MOVIE, name); #endif } } @@ -100,26 +103,26 @@ public ScaledBink(string name, PointF pos, SizeF size) : base(pos, size) /// public override void Draw() { - if (id == -1) + if (Id == -1) { return; } #if ALTV - Alt.Natives.PlayBinkMovie(id); - Alt.Natives.DrawBinkMovie(id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); + Alt.Natives.PlayBinkMovie(Id); + Alt.Natives.DrawBinkMovie(Id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); #elif FIVEM - API.PlayBinkMovie(id); - API.DrawBinkMovie(id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); + API.PlayBinkMovie(Id); + API.DrawBinkMovie(Id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); #elif RAGEMP - Invoker.Invoke(0xE178310643033958, id); - Invoker.Invoke(0x7118E83EEB9F7238, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); + Invoker.Invoke(0xE178310643033958, Id); + Invoker.Invoke(0x7118E83EEB9F7238, Id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); #elif RPH - NativeFunction.CallByHash(0xE178310643033958, id); - NativeFunction.CallByHash(0x7118E83EEB9F7238, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); + NativeFunction.CallByHash(0xE178310643033958, Id); + NativeFunction.CallByHash(0x7118E83EEB9F7238, Id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); #elif SHVDN3 || SHVDNC - Function.Call(Hash.PLAY_BINK_MOVIE, id); - Function.Call(Hash.DRAW_BINK_MOVIE, id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); + Function.Call(Hash.PLAY_BINK_MOVIE, Id); + Function.Call(Hash.DRAW_BINK_MOVIE, Id, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, 0.0f, 255, 255, 255, 255); #endif } /// @@ -130,21 +133,21 @@ public override void Draw() /// public void Stop() { - if (id == -1) + if (Id == -1) { return; } #if ALTV - Alt.Natives.StopBinkMovie(id); + Alt.Natives.StopBinkMovie(Id); #elif FIVEM - API.StopBinkMovie(id); + API.StopBinkMovie(Id); #elif RAGEMP - Invoker.Invoke(0x63606A61DE68898A, id); + Invoker.Invoke(0x63606A61DE68898A, Id); #elif RPH - NativeFunction.CallByHash(0x63606A61DE68898A, id); + NativeFunction.CallByHash(0x63606A61DE68898A, Id); #elif SHVDN3 || SHVDNC - Function.Call(Hash.STOP_BINK_MOVIE, id); + Function.Call(Hash.STOP_BINK_MOVIE, Id); #endif } /// @@ -152,24 +155,24 @@ public void Stop() /// public void Dispose() { - if (id == -1) + if (Id == -1) { return; } #if ALTV - Alt.Natives.ReleaseBinkMovie(id); + Alt.Natives.ReleaseBinkMovie(Id); #elif FIVEM - API.ReleaseBinkMovie(id); + API.ReleaseBinkMovie(Id); #elif RAGEMP - Invoker.Invoke(0x04D950EEFA4EED8C, id); + Invoker.Invoke(0x04D950EEFA4EED8C, Id); #elif RPH - NativeFunction.CallByHash(0x04D950EEFA4EED8C, id); + NativeFunction.CallByHash(0x04D950EEFA4EED8C, Id); #elif SHVDN3 || SHVDNC - Function.Call(Hash.RELEASE_BINK_MOVIE, id); + Function.Call(Hash.RELEASE_BINK_MOVIE, Id); #endif - id = -1; + Id = -1; } /// public override void Recalculate() From 3c8022b7eb2d793e7d1c04b25fadf267ecf86e06 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Sat, 16 Dec 2023 22:17:31 -0300 Subject: [PATCH 28/48] Make sure that the argument parameters are not null Closes #124 --- LemonUI/Scaleform/BaseScaleform.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LemonUI/Scaleform/BaseScaleform.cs b/LemonUI/Scaleform/BaseScaleform.cs index c7cb557..e0c3725 100644 --- a/LemonUI/Scaleform/BaseScaleform.cs +++ b/LemonUI/Scaleform/BaseScaleform.cs @@ -117,7 +117,11 @@ private void CallFunctionBase(string function, params object[] parameters) foreach (object obj in parameters) { - if (obj is int objInt) + if (obj == null) + { + throw new ArgumentNullException(nameof(parameters), "Unexpected null function argument in parameters."); + } + else if (obj is int objInt) { #if FIVEM API.ScaleformMovieMethodAddParamInt(objInt); From c38f79ce21007bb731185837440a48a46db6fe63 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 20:03:35 -0300 Subject: [PATCH 29/48] Added basic class for ytd based animations --- LemonUI/Elements/ScaledAnim.cs | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 LemonUI/Elements/ScaledAnim.cs diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs new file mode 100644 index 0000000..8387ae0 --- /dev/null +++ b/LemonUI/Elements/ScaledAnim.cs @@ -0,0 +1,45 @@ +using System.Drawing; + +namespace LemonUI.Elements +{ + /// + /// A scaled animation using YTD files with all of the frames. + /// + public class ScaledAnim : BaseElement + { + #region Properties + + /// + /// The dictionary that contains the textures. + /// + public string Dict { get; set; } + + #endregion + + #region Constructors + + /// + /// Creates a new dictionary based animation. + /// + /// The texture dictionary (YTD) to use. + /// The position of the animation. + /// The size of the animation. + public ScaledAnim(string dict, PointF pos, SizeF size) : base(pos, size) + { + Dict = dict; + } + + #endregion + + #region Functions + + /// + /// Draws the animation. + /// + public override void Draw() + { + } + + #endregion + } +} From 62f6d7c068e2f50afc59aee5c6decb9c1a64459a Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 20:07:26 -0300 Subject: [PATCH 30/48] Make the BaseElement properties virtual Fixes #150 --- LemonUI/Elements/BaseElement.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/LemonUI/Elements/BaseElement.cs b/LemonUI/Elements/BaseElement.cs index 208911b..d68def8 100644 --- a/LemonUI/Elements/BaseElement.cs +++ b/LemonUI/Elements/BaseElement.cs @@ -34,12 +34,9 @@ public abstract class BaseElement : I2Dimensional /// /// The Position of the drawable. /// - public PointF Position + public virtual PointF Position { - get - { - return literalPosition; - } + get => literalPosition; set { literalPosition = value; @@ -49,12 +46,9 @@ public PointF Position /// /// The Size of the drawable. /// - public SizeF Size + public virtual SizeF Size { - get - { - return literalSize; - } + get => literalSize; set { literalSize = value; @@ -64,11 +58,11 @@ public SizeF Size /// /// The Color of the drawable. /// - public Color Color { get; set; } = Color.FromArgb(255, 255, 255, 255); + public virtual Color Color { get; set; } = Color.FromArgb(255, 255, 255, 255); /// /// The rotation of the drawable. /// - public float Heading { get; set; } = 0; + public virtual float Heading { get; set; } = 0; #endregion From b2becb91ecccaa3e273f12348a3aee46ace57a54 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 22:38:39 -0300 Subject: [PATCH 31/48] Added texture field --- LemonUI/Elements/ScaledAnim.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 8387ae0..c31d673 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -7,6 +7,12 @@ namespace LemonUI.Elements /// public class ScaledAnim : BaseElement { + #region Fields + + private ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); + + #endregion + #region Properties /// From cb2c2c574fdf107dcebdc461ecef93795e3ab1d8 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 22:39:16 -0300 Subject: [PATCH 32/48] Make the dict property use the texture --- LemonUI/Elements/ScaledAnim.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index c31d673..b4d92f2 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -1,3 +1,4 @@ +using System; using System.Drawing; namespace LemonUI.Elements @@ -18,7 +19,11 @@ public class ScaledAnim : BaseElement /// /// The dictionary that contains the textures. /// - public string Dict { get; set; } + public string Dict + { + get => texture.Dictionary; + set => texture.Dictionary = value ?? throw new ArgumentNullException(nameof(value)); + } #endregion @@ -32,7 +37,7 @@ public class ScaledAnim : BaseElement /// The size of the animation. public ScaledAnim(string dict, PointF pos, SizeF size) : base(pos, size) { - Dict = dict; + texture.Dictionary = dict ?? throw new ArgumentNullException(nameof(dict)); } #endregion From ce98f5425b197d64852bbbee22123f2018b4b471 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 22:39:41 -0300 Subject: [PATCH 33/48] Make the texture readonly --- LemonUI/Elements/ScaledAnim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index b4d92f2..5e68106 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -10,7 +10,7 @@ public class ScaledAnim : BaseElement { #region Fields - private ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); + private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); #endregion From 5661453272f14298de103a89577e9432467a769a Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 22:41:34 -0300 Subject: [PATCH 34/48] Renamed Dict to Dictionary --- LemonUI/Elements/ScaledAnim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 5e68106..04021e6 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -19,7 +19,7 @@ public class ScaledAnim : BaseElement /// /// The dictionary that contains the textures. /// - public string Dict + public string Dictionary { get => texture.Dictionary; set => texture.Dictionary = value ?? throw new ArgumentNullException(nameof(value)); From c099cda5136b0583c402019c6c48688e31cc8807 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Mon, 18 Dec 2023 23:17:49 -0300 Subject: [PATCH 35/48] Added property to set the framerate and frame time --- LemonUI/Elements/ScaledAnim.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 04021e6..fbe6584 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -11,6 +11,8 @@ public class ScaledAnim : BaseElement #region Fields private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); + private float frameRate; + private int frameTime; #endregion @@ -24,6 +26,18 @@ public string Dictionary get => texture.Dictionary; set => texture.Dictionary = value ?? throw new ArgumentNullException(nameof(value)); } + /// + /// The total number of frames per second. + /// + public float FrameRate + { + get => frameRate; + set + { + frameRate = value; + frameTime = (int)((1.0f / value) * 1000); + } + } #endregion From 1a2b9d960315b49f110db2999e4f661dc24d1dc2 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:47:54 -0300 Subject: [PATCH 36/48] Removed the frame time calculation --- LemonUI/Elements/ScaledAnim.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index fbe6584..72ab65b 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -1,3 +1,14 @@ +#if ALTV +using AltV.Net.Client; +#elif FIVEM +using CitizenFX.Core; +#elif RAGEMP +using RAGE.Game; +#elif RPH +using Rage.Native; +#elif SHVDN3 || SHVDNC +using GTA; +#endif using System; using System.Drawing; @@ -12,7 +23,6 @@ public class ScaledAnim : BaseElement private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); private float frameRate; - private int frameTime; #endregion @@ -32,11 +42,7 @@ public string Dictionary public float FrameRate { get => frameRate; - set - { - frameRate = value; - frameTime = (int)((1.0f / value) * 1000); - } + set => frameRate = value; } #endregion From f00b67fe031ebeba433ed1e7eb4fb7d2bbb3f56c Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:49:12 -0300 Subject: [PATCH 37/48] Added property to set the duration --- LemonUI/Elements/ScaledAnim.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 72ab65b..472171f 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -23,6 +23,7 @@ public class ScaledAnim : BaseElement private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); private float frameRate; + private int duration; #endregion @@ -44,6 +45,22 @@ public float FrameRate get => frameRate; set => frameRate = value; } + /// + /// The duration of the animation in milliseconds. + /// + public int Duration + { + get => duration; + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "The duration can't be under zero."); + } + + duration = value; + } + } #endregion From 84fb739910c8ea6a767bcf7167727b4be26d2882 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:50:43 -0300 Subject: [PATCH 38/48] Added calculation of the current frame --- LemonUI/Elements/ScaledAnim.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 472171f..73c8fa7 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -23,6 +23,7 @@ public class ScaledAnim : BaseElement private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); private float frameRate; + private int start = 0; private int duration; #endregion @@ -86,6 +87,32 @@ public ScaledAnim(string dict, PointF pos, SizeF size) : base(pos, size) /// public override void Draw() { + if (Duration <= 0) + { + return; + } + +#if ALTV + int time = Alt.Natives.GetGameTimer(); +#elif RAGEMP + int time = Misc.GetGameTimer(); +#elif RPH + int time = NativeFunction.CallByHash(0x9CD27B0045628463); +#elif FIVEM || SHVDN3 || SHVDNC + int time = Game.GameTime; +#endif + + int end = start + Duration; + + if (start == 0 || end <= time) + { + start = time; + } + + float progress = (time - (float)start) / Duration; + int totalFrames = (int)((duration / 1000.0f) * frameRate); + int currentFrame = (int)(totalFrames * progress); + texture.Texture = currentFrame.ToString(); } #endregion From f52abb4cc74f52a9bdd60183608e822a272ce15f Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:51:02 -0300 Subject: [PATCH 39/48] Added texture drawing --- LemonUI/Elements/ScaledAnim.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 73c8fa7..4071fda 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -113,6 +113,8 @@ public override void Draw() int totalFrames = (int)((duration / 1000.0f) * frameRate); int currentFrame = (int)(totalFrames * progress); texture.Texture = currentFrame.ToString(); + + texture.Draw(); } #endregion From 587f76184d3fce41b4dcb4603bdc5b6f2467b4f9 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:54:58 -0300 Subject: [PATCH 40/48] Added properties for Position, Size, Color and Heading --- LemonUI/Elements/ScaledAnim.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 4071fda..d8b7734 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -30,6 +30,38 @@ public class ScaledAnim : BaseElement #region Properties + /// + /// The position of this animation. + /// + public override PointF Position + { + get => texture.Position; + set => texture.Position = value; + } + /// + /// The size of this animation. + /// + public override SizeF Size + { + get => texture.Size; + set => texture.Size = value; + } + /// + /// The color of this animation. + /// + public override Color Color + { + get => texture.Color; + set => texture.Color = value; + } + /// + /// The rotation of this animation. + /// + public override float Heading + { + get => texture.Heading; + set => texture.Heading = value; + } /// /// The dictionary that contains the textures. /// From 5cf4e43b0edabcaa024be30cbf33c2ac8f3d3c46 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:56:08 -0300 Subject: [PATCH 41/48] Make sure that the framerate does not goes under zero --- LemonUI/Elements/ScaledAnim.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index d8b7734..3a4a120 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -76,7 +76,15 @@ public string Dictionary public float FrameRate { get => frameRate; - set => frameRate = value; + set + { + if (frameRate <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "The Frame Rate can't be equal or lower to zero."); + } + + frameRate = value; + } } /// /// The duration of the animation in milliseconds. From 9565d63e513efa20778da97e857f3be039499e35 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 01:58:28 -0300 Subject: [PATCH 42/48] Added simpler ScaledAnim constructors --- LemonUI/Elements/ScaledAnim.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 3a4a120..41b3f76 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -107,6 +107,22 @@ public int Duration #region Constructors + /// + /// Creates a new dictionary based animation. + /// + /// The texture dictionary (YTD) to use. + public ScaledAnim(string dict) : this(dict, PointF.Empty, SizeF.Empty) + { + } + /// + /// Creates a new dictionary based animation. + /// + /// The texture dictionary (YTD) to use. + /// The size of the animation. + public ScaledAnim(string dict, SizeF size) : this(dict, PointF.Empty, size) + { + texture.Dictionary = dict ?? throw new ArgumentNullException(nameof(dict)); + } /// /// Creates a new dictionary based animation. /// From 328fbffda8230823d07f69805d083ec3aacbaaa8 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 02:09:45 -0300 Subject: [PATCH 43/48] Fixed FrameRate check --- LemonUI/Elements/ScaledAnim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 41b3f76..a27a5b3 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -78,7 +78,7 @@ public float FrameRate get => frameRate; set { - if (frameRate <= 0) + if (value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), "The Frame Rate can't be equal or lower to zero."); } From a18842ece17af269a6ea1c589bd250f97a9025ac Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 02:34:41 -0300 Subject: [PATCH 44/48] Inherit from a regular ScaledTexture To prevent further issues down the line --- LemonUI/Elements/ScaledAnim.cs | 52 ++++------------------------------ 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index a27a5b3..5706760 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -17,11 +17,10 @@ namespace LemonUI.Elements /// /// A scaled animation using YTD files with all of the frames. /// - public class ScaledAnim : BaseElement + public class ScaledAnim : ScaledTexture { #region Fields - private readonly ScaledTexture texture = new ScaledTexture(string.Empty, string.Empty); private float frameRate; private int start = 0; private int duration; @@ -30,46 +29,6 @@ public class ScaledAnim : BaseElement #region Properties - /// - /// The position of this animation. - /// - public override PointF Position - { - get => texture.Position; - set => texture.Position = value; - } - /// - /// The size of this animation. - /// - public override SizeF Size - { - get => texture.Size; - set => texture.Size = value; - } - /// - /// The color of this animation. - /// - public override Color Color - { - get => texture.Color; - set => texture.Color = value; - } - /// - /// The rotation of this animation. - /// - public override float Heading - { - get => texture.Heading; - set => texture.Heading = value; - } - /// - /// The dictionary that contains the textures. - /// - public string Dictionary - { - get => texture.Dictionary; - set => texture.Dictionary = value ?? throw new ArgumentNullException(nameof(value)); - } /// /// The total number of frames per second. /// @@ -121,7 +80,6 @@ public ScaledAnim(string dict) : this(dict, PointF.Empty, SizeF.Empty) /// The size of the animation. public ScaledAnim(string dict, SizeF size) : this(dict, PointF.Empty, size) { - texture.Dictionary = dict ?? throw new ArgumentNullException(nameof(dict)); } /// /// Creates a new dictionary based animation. @@ -129,9 +87,9 @@ public ScaledAnim(string dict, SizeF size) : this(dict, PointF.Empty, size) /// The texture dictionary (YTD) to use. /// The position of the animation. /// The size of the animation. - public ScaledAnim(string dict, PointF pos, SizeF size) : base(pos, size) + public ScaledAnim(string dict, PointF pos, SizeF size) : base(pos, size, dict, string.Empty) { - texture.Dictionary = dict ?? throw new ArgumentNullException(nameof(dict)); + Dictionary = dict ?? throw new ArgumentNullException(nameof(dict)); } #endregion @@ -168,9 +126,9 @@ public override void Draw() float progress = (time - (float)start) / Duration; int totalFrames = (int)((duration / 1000.0f) * frameRate); int currentFrame = (int)(totalFrames * progress); - texture.Texture = currentFrame.ToString(); + Texture = currentFrame.ToString(); - texture.Draw(); + base.Draw(); } #endregion From 5af8c5f99f53205afe89837a4f9bbaab107997a3 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 02:56:01 -0300 Subject: [PATCH 45/48] Make sure that no frames over or under the total are played --- LemonUI/Elements/ScaledAnim.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/LemonUI/Elements/ScaledAnim.cs b/LemonUI/Elements/ScaledAnim.cs index 5706760..0a46989 100644 --- a/LemonUI/Elements/ScaledAnim.cs +++ b/LemonUI/Elements/ScaledAnim.cs @@ -125,7 +125,19 @@ public override void Draw() float progress = (time - (float)start) / Duration; int totalFrames = (int)((duration / 1000.0f) * frameRate); - int currentFrame = (int)(totalFrames * progress); + int currentFrame = (int)(totalFrames * progress) + 1; + + if (progress < 0) + { + currentFrame = 1; + start = time; + } + else if (currentFrame >= totalFrames) + { + currentFrame = totalFrames; + start = time; + } + Texture = currentFrame.ToString(); base.Draw(); From 3bd459d64dec17ab60543f13063804adaea7b930 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 03:11:58 -0300 Subject: [PATCH 46/48] Added null checks missing from #123 --- LemonUI/Elements/ScaledTexture.cs | 25 +++++++++++++++++++++---- LemonUI/Scaleform/BaseScaleform.cs | 12 +++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/LemonUI/Elements/ScaledTexture.cs b/LemonUI/Elements/ScaledTexture.cs index 30fda74..1913a94 100644 --- a/LemonUI/Elements/ScaledTexture.cs +++ b/LemonUI/Elements/ScaledTexture.cs @@ -9,6 +9,7 @@ #elif ALTV using AltV.Net.Client; #endif +using System; using System.Drawing; namespace LemonUI.Elements @@ -18,16 +19,32 @@ namespace LemonUI.Elements /// public class ScaledTexture : BaseElement { + #region Fields + + private string dictionary; + private string texture; + + #endregion + #region Properties /// /// The dictionary where the texture is loaded. /// - public string Dictionary { get; set; } + public string Dictionary + { + get => dictionary; + set => dictionary = value ?? throw new ArgumentNullException(nameof(value)); + } + /// /// The texture to draw from the dictionary. /// - public string Texture { get; set; } + public string Texture + { + get => texture; + set => texture = value ?? throw new ArgumentNullException(nameof(value)); + } #endregion @@ -50,8 +67,8 @@ public ScaledTexture(string dictionary, string texture) : this(PointF.Empty, Siz /// The texture to draw. public ScaledTexture(PointF pos, SizeF size, string dictionary, string texture) : base(pos, size) { - Dictionary = dictionary; - Texture = texture; + Dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary)); + Texture = texture ?? throw new ArgumentNullException(nameof(texture)); Request(); } diff --git a/LemonUI/Scaleform/BaseScaleform.cs b/LemonUI/Scaleform/BaseScaleform.cs index e0c3725..4675aa5 100644 --- a/LemonUI/Scaleform/BaseScaleform.cs +++ b/LemonUI/Scaleform/BaseScaleform.cs @@ -82,7 +82,7 @@ public bool IsLoaded /// The Scalform object. public BaseScaleform(string sc) { - Name = sc; + Name = sc ?? throw new ArgumentNullException(nameof(sc)); #if FIVEM Handle = API.RequestScaleformMovie(Name); @@ -103,6 +103,16 @@ public BaseScaleform(string sc) private void CallFunctionBase(string function, params object[] parameters) { + if (function == null) + { + throw new ArgumentNullException(nameof(function), "The function name is null."); + } + + if (string.IsNullOrWhiteSpace(function)) + { + throw new ArgumentOutOfRangeException(nameof(function), "The function name is empty or white space."); + } + #if FIVEM API.BeginScaleformMovieMethod(Handle, function); #elif ALTV From e97af6cda4a43c74fd49eec9244f64861804abf1 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 15:33:51 -0300 Subject: [PATCH 47/48] Switch to unsafe blocks for SHVDN Closes #119 --- LemonUI/Scaleform/BaseScaleform.cs | 4 ++-- LemonUI/Tools/SafeZone.cs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/LemonUI/Scaleform/BaseScaleform.cs b/LemonUI/Scaleform/BaseScaleform.cs index 4675aa5..9ee859e 100644 --- a/LemonUI/Scaleform/BaseScaleform.cs +++ b/LemonUI/Scaleform/BaseScaleform.cs @@ -419,9 +419,9 @@ public void Dispose() NativeFunction.CallByHash(0x6DD8F5AA635EB4B2, idPtr); } #elif SHVDN3 || SHVDNC - using (OutputArgument idPtr = new OutputArgument(id)) + unsafe { - Function.Call(Hash.SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED, idPtr); + Function.Call(Hash.SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED, &id); } #endif } diff --git a/LemonUI/Tools/SafeZone.cs b/LemonUI/Tools/SafeZone.cs index 4ddfa8d..e78b3cc 100644 --- a/LemonUI/Tools/SafeZone.cs +++ b/LemonUI/Tools/SafeZone.cs @@ -123,12 +123,9 @@ public static PointF GetSafePosition(float x, float y) realY = argY.GetValue(); } #elif SHVDN3 || SHVDNC - using (OutputArgument argX = new OutputArgument()) - using (OutputArgument argY = new OutputArgument()) + unsafe { - Function.Call((Hash)0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); // _GET_SCRIPT_GFX_POSITION - realX = argX.GetResult(); - realY = argY.GetResult(); + Function.Call(Hash.GET_SCRIPT_GFX_ALIGN_POSITION, relativeX, relativeY, &realX, &realY); } #endif From 9f12ff32e01b93ceba57f0a03c7e8055ae6f1784 Mon Sep 17 00:00:00 2001 From: Hannele Ruiz Date: Tue, 19 Dec 2023 16:51:29 -0300 Subject: [PATCH 48/48] Fixed MsPerGameMinute being used instead of GetGameTimer in Alt:V Fixes #151 --- LemonUI/Menus/NativeMenu.cs | 2 +- LemonUI/Scaleform/BigMessage.cs | 4 ++-- LemonUI/Scaleform/BruteForce.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index e61d1d9..bde1f97 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -1166,7 +1166,7 @@ private void ProcessControls() #if RAGEMP int time = Misc.GetGameTimer(); #elif ALTV - int time = Alt.MsPerGameMinute; + int time = Alt.Natives.GetGameTimer(); #elif RPH uint time = Game.GameTime; #else diff --git a/LemonUI/Scaleform/BigMessage.cs b/LemonUI/Scaleform/BigMessage.cs index 1692e14..d7333ce 100644 --- a/LemonUI/Scaleform/BigMessage.cs +++ b/LemonUI/Scaleform/BigMessage.cs @@ -281,7 +281,7 @@ public void FadeOut(int time) #if RAGEMP uint currentTime = (uint)Misc.GetGameTimer(); #elif ALTV - uint currentTime = (uint)Alt.MsPerGameMinute; + uint currentTime = (uint)Alt.Natives.GetGameTimer(); #elif RPH uint currentTime = Game.GameTime; #else @@ -295,7 +295,7 @@ public override void DrawFullScreen() #if RAGEMP uint time = (uint)Misc.GetGameTimer(); #elif ALTV - uint time = (uint)Alt.MsPerGameMinute; + uint time = (uint)Alt.Natives.GetGameTimer(); #elif RPH uint time = Game.GameTime; #else diff --git a/LemonUI/Scaleform/BruteForce.cs b/LemonUI/Scaleform/BruteForce.cs index 6fc0009..93baedc 100644 --- a/LemonUI/Scaleform/BruteForce.cs +++ b/LemonUI/Scaleform/BruteForce.cs @@ -199,7 +199,7 @@ public void Reset() #if RAGEMP int time = Misc.GetGameTimer(); #elif ALTV - int time = Alt.MsPerGameMinute; + int time = Alt.Natives.GetGameTimer(); #elif RPH uint time = Game.GameTime; #else @@ -237,7 +237,7 @@ public override void Update() #if RAGEMP int time = Misc.GetGameTimer(); #elif ALTV - int time = Alt.MsPerGameMinute; + int time = Alt.Natives.GetGameTimer(); #elif RPH uint time = Game.GameTime; #else