diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06a66a27..e507ef5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,6 +6,12 @@ on: push: pull_request: +permissions: + contents: write + id-token: write + pages: write + packages: write + jobs: lint-and-compile: strategy: @@ -13,54 +19,81 @@ jobs: configuration: [Debug, Release] runs-on: ubuntu-22.04 steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v2.1.0 + - uses: actions/checkout@v3 + - uses: actions/setup-dotnet@v2.1.0 with: dotnet-version: "7.0.x" - - name: Restore NuGet Packages - run: dotnet restore ${{ github.event.repository.name }}.sln - - name: Patch csproj version - uses: justalemon/VersionPatcher@v0.4 + - run: dotnet restore ${{ github.event.repository.name }}.sln + - uses: justalemon/VersionPatcher@v0.7.1 with: - version: 1.2.2.${{ github.run_number }} + version: 1.10.0.${{ github.run_number }} use-tag: true - csproj-files: "**/**.csproj" - - name: Compile + csproj-files: "**/*.csproj" + - run: dotnet build ${{ github.event.repository.name }}.sln -c ${{ matrix.configuration }} working-directory: ${{ env.GITHUB_WORKSPACE }} - run: dotnet build ${{ github.event.repository.name }}.sln -c ${{ matrix.configuration }} - - name: Upload Artifact - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}.${{ matrix.configuration }} path: bin/${{ matrix.configuration }} + docs: + runs-on: ubuntu-22.04 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + needs: + - lint-and-compile + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-dotnet@v2.1.0 + with: + dotnet-version: "7.0.x" + - uses: actions/download-artifact@v3 + with: + name: ${{ github.event.repository.name }}.Release + path: bin/Release + - run: ls -R + working-directory: bin/Release + - run: dotnet tool update -g docfx + - run: docfx docs/docfx.json + - uses: actions/upload-pages-artifact@v1.0.7 + with: + path: "docs/_site" + - uses: actions/deploy-pages@v1.2.4 + github-package-registry: + runs-on: ubuntu-22.04 + if: ${{ github.ref == 'refs/heads/master' }} + needs: + - lint-and-compile + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-dotnet@v2.1.0 + with: + dotnet-version: "7.0.x" + - uses: actions/download-artifact@v3 + with: + name: ${{ github.event.repository.name }}.Release + path: bin/Release + - run: ls -R + working-directory: bin/Release + - run: 7z a ${{ github.event.repository.name }}.zip ${{ github.workspace }}/bin/Release/* + - run: dotnet nuget push "**/*.nupkg" -s 'https://nuget.pkg.github.com/${{ github.event.repository.owner.name }}/index.json' -k ${{ secrets.GITHUB_TOKEN }} deploy: runs-on: ubuntu-22.04 if: ${{ github.event_name == 'release' }} needs: - lint-and-compile steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v2.1.0 + - uses: actions/checkout@v3 + - uses: actions/setup-dotnet@v2.1.0 with: dotnet-version: "7.0.x" - - name: Download the Artifact - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}.Release path: bin/Release - - name: List Everything - run: ls -R + - run: ls -R working-directory: bin/Release - - name: Repackage Files - run: 7z a ${{ github.event.repository.name }}.zip ${{ github.workspace }}/bin/Release/* - - name: Deploy NuGet - run: dotnet nuget push "**/*.nupkg" -s 'https://api.nuget.org/v3/index.json' -k ${{secrets.NUGET}} - - name: Create Release - uses: ncipollo/release-action@v1.10.0 + - run: 7z a ${{ github.event.repository.name }}.zip ${{ github.workspace }}/bin/Release/* + - run: dotnet nuget push "**/*.nupkg" -s 'https://api.nuget.org/v3/index.json' -k ${{ secrets.NUGET }} + - uses: ncipollo/release-action@v1.10.0 with: allowUpdates: true artifactErrorsFailBuild: true diff --git a/.gitignore b/.gitignore index dfcfd56f..6c4a038a 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,6 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +# Remove JetBrains project files +.idea/ \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 29403eb3..3a81bc21 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - + diff --git a/LICENSE b/LICENSE index 70778459..3948a7f9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2021 Hannele Ruiz +Copyright (c) 2020-2023 Hannele Ruiz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/LemonUI.AltV.Async/LemonUI.AltV.Async.csproj b/LemonUI.AltV.Async/LemonUI.AltV.Async.csproj new file mode 100644 index 00000000..1f9922c4 --- /dev/null +++ b/LemonUI.AltV.Async/LemonUI.AltV.Async.csproj @@ -0,0 +1,45 @@ + + + + net6.0 + false + true + $(AssemblyName) + ALTV,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\AltV\ + AnyCPU + embedded + true + false + false + + true + $(OutputPath)\$(AssemblyName).xml + + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI + UI system for Grand Theft Auto V. This package is for AltV Client (Asynchronous). + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS + + + + + + + + compile + + + + diff --git a/LemonUI.AltV/LemonUI.AltV.csproj b/LemonUI.AltV/LemonUI.AltV.csproj new file mode 100644 index 00000000..d9751d36 --- /dev/null +++ b/LemonUI.AltV/LemonUI.AltV.csproj @@ -0,0 +1,45 @@ + + + + net6.0 + false + true + $(AssemblyName) + ALTV,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\AltV\ + AnyCPU + embedded + true + false + false + + true + $(OutputPath)\$(AssemblyName).xml + + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI + UI system for Grand Theft Auto V. This package is for AltV Client. + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS + + + + + + + + compile + + + + diff --git a/LemonUI.FiveM/LemonUI.FiveM.csproj b/LemonUI.FiveM/LemonUI.FiveM.csproj index 3d3ed729..e45460d9 100644 --- a/LemonUI.FiveM/LemonUI.FiveM.csproj +++ b/LemonUI.FiveM/LemonUI.FiveM.csproj @@ -1,24 +1,45 @@ + - FiveM net452 - FIVEM - - - + false + true + $(AssemblyName) + FIVEM,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\FiveM\ + AnyCPU embedded true - + false + false - + true + $(OutputPath)\$(AssemblyName).xml - + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI UI system for Grand Theft Auto V. This package is for FiveM Client. + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS - + + + + compile + diff --git a/LemonUI.RageMP/LemonUI.RageMP.csproj b/LemonUI.RageMP/LemonUI.RageMP.csproj index f3e6e4a0..bc5cb067 100644 --- a/LemonUI.RageMP/LemonUI.RageMP.csproj +++ b/LemonUI.RageMP/LemonUI.RageMP.csproj @@ -1,30 +1,49 @@ + - RageMP netcoreapp2.2 - RAGEMP - - - - true + false + true + $(AssemblyName) + RAGEMP,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\RageMP\ x64 + portable + true + false false - - + true + $(OutputPath)\$(AssemblyName).xml - + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI UI system for Grand Theft Auto V. This package is for RageMP. + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS - + + + + compile - + diff --git a/LemonUI.RagePluginHook/LemonUI.RagePluginHook.csproj b/LemonUI.RagePluginHook/LemonUI.RagePluginHook.csproj index f96f29b9..783dba26 100644 --- a/LemonUI.RagePluginHook/LemonUI.RagePluginHook.csproj +++ b/LemonUI.RagePluginHook/LemonUI.RagePluginHook.csproj @@ -1,23 +1,45 @@ + - RPH net472 - RPH - - - + false + true + $(AssemblyName) + RPH,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\RPH\ x64 - - - + portable + true + true + false - + true + $(OutputPath)\$(AssemblyName).xml + + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI UI system for Grand Theft Auto V. This package is for RagePluginHook (RPH). + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS + + + compile + diff --git a/LemonUI.SHVDN3/LemonUI.SHVDN3.csproj b/LemonUI.SHVDN3/LemonUI.SHVDN3.csproj index 5cee619d..83a07667 100644 --- a/LemonUI.SHVDN3/LemonUI.SHVDN3.csproj +++ b/LemonUI.SHVDN3/LemonUI.SHVDN3.csproj @@ -1,23 +1,45 @@ + - SHVDN3 net48 - SHVDN3 - - - + false + true + $(AssemblyName) + SHVDN3,CLIENT + 1.10.0 + $(SolutionDir)bin\$(Configuration)\SHVDN3\ x64 - + portable + true + true + false - + true + $(OutputPath)\$(AssemblyName).xml - + true + true + logo.png + $(ProjectName) + Hannele "Lemon" Ruiz + Hannele "Lemon" Ruiz + LemonUI UI system for Grand Theft Auto V. This package is for ScriptHookVDotNet3. + MIT + https://github.com/justalemon/LemonUI + https://github.com/justalemon/LemonUI.git + git + en-US + $(SolutionDir)bin\$(Configuration)\FOR DEVELOPERS - + + + + compile + diff --git a/LemonUI.sln b/LemonUI.sln index 4a806157..6941682d 100644 --- a/LemonUI.sln +++ b/LemonUI.sln @@ -13,6 +13,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LemonUI.RageMP", "LemonUI.R EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LemonUI.SHVDNC", "LemonUI.SHVDNC\LemonUI.SHVDNC.csproj", "{3B49A7F9-96FF-4448-96FF-DAAA68E9B0CF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LemonUI.AltV", "LemonUI.AltV\LemonUI.AltV.csproj", "{23811603-B595-4AB2-ADC7-25F0C6920193}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LemonUI.AltV.Async", "LemonUI.AltV.Async\LemonUI.AltV.Async.csproj", "{F2761304-2B83-451F-B7BD-F7F752233A01}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +43,14 @@ Global {3B49A7F9-96FF-4448-96FF-DAAA68E9B0CF}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B49A7F9-96FF-4448-96FF-DAAA68E9B0CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B49A7F9-96FF-4448-96FF-DAAA68E9B0CF}.Release|Any CPU.Build.0 = Release|Any CPU + {23811603-B595-4AB2-ADC7-25F0C6920193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23811603-B595-4AB2-ADC7-25F0C6920193}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23811603-B595-4AB2-ADC7-25F0C6920193}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23811603-B595-4AB2-ADC7-25F0C6920193}.Release|Any CPU.Build.0 = Release|Any CPU + {F2761304-2B83-451F-B7BD-F7F752233A01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2761304-2B83-451F-B7BD-F7F752233A01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2761304-2B83-451F-B7BD-F7F752233A01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2761304-2B83-451F-B7BD-F7F752233A01}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/LemonUI/CancelEventArgs.cs b/LemonUI/CancelEventArgs.cs index 3e298df7..8db4c253 100644 --- a/LemonUI/CancelEventArgs.cs +++ b/LemonUI/CancelEventArgs.cs @@ -13,23 +13,30 @@ namespace LemonUI // Previously System.ComponentModel /// public class CancelEventArgs : EventArgs { + #region Properties + /// /// Gets or sets a value indicating whether we should cancel the operation or not /// public bool Cancel { get; set; } + #endregion + + #region Constructors + /// /// Default constructor /// public CancelEventArgs() { } - /// /// Helper constructor /// /// public CancelEventArgs(bool cancel) => Cancel = cancel; + + #endregion } } #endif diff --git a/LemonUI/Control.cs b/LemonUI/Control.cs new file mode 100644 index 00000000..463fe57d --- /dev/null +++ b/LemonUI/Control.cs @@ -0,0 +1,369 @@ +// NO MERGE + +#if ALTV + +namespace LemonUI +{ + public enum Control + { + NextCamera = 0, + LookLr = 1, + LookUd = 2, + LookUpOnly = 3, + LookDownOnly = 4, + LookLeftOnly = 5, + LookRightOnly = 6, + CinematicSlowmo = 7, + ScriptedFlyUd = 8, + ScriptedFlyLr = 9, + ScriptedFlyZup = 10, + ScriptedFlyZdown = 11, + WeaponWheelUd = 12, + WeaponWheelLr = 13, + WeaponWheelNext = 14, + WeaponWheelPrev = 15, + SelectNextWeapon = 16, + SelectPrevWeapon = 17, + SkipCutscene = 18, + CharacterWheel = 19, + MultiplayerInfo = 20, + Sprint = 21, + Jump = 22, + Enter = 23, + Attack = 24, + Aim = 25, + LookBehind = 26, + Phone = 27, + SpecialAbility = 28, + SpecialAbilitySecondary = 29, + MoveLr = 30, + MoveUd = 31, + MoveUpOnly = 32, + MoveDownOnly = 33, + MoveLeftOnly = 34, + MoveRightOnly = 35, + Duck = 36, + SelectWeapon = 37, + Pickup = 38, + SniperZoom = 39, + SniperZoomInOnly = 40, + SniperZoomOutOnly = 41, + SniperZoomInSecondary = 42, + SniperZoomOutSecondary = 43, + Cover = 44, + Reload = 45, + Talk = 46, + Detonate = 47, + HudSpecial = 48, + Arrest = 49, + AccurateAim = 50, + Context = 51, + ContextSecondary = 52, + WeaponSpecial = 53, + WeaponSpecialTwo = 54, + Dive = 55, + DropWeapon = 56, + DropAmmo = 57, + ThrowGrenade = 58, + VehMoveLr = 59, + VehMoveUd = 60, + VehMoveUpOnly = 61, + VehMoveDownOnly = 62, + VehMoveLeftOnly = 63, + VehMoveRightOnly = 64, + VehSpecial = 65, + VehGunLr = 66, + VehGunUd = 67, + VehAim = 68, + VehAttack = 69, + VehAttack2 = 70, + VehAccelerate = 71, + VehBrake = 72, + VehDuck = 73, + VehHeadlight = 74, + VehExit = 75, + VehHandbrake = 76, + VehHotwireLeft = 77, + VehHotwireRight = 78, + VehLookBehind = 79, + VehCinCam = 80, + VehNextRadio = 81, + VehPrevRadio = 82, + VehNextRadioTrack = 83, + VehPrevRadioTrack = 84, + VehRadioWheel = 85, + VehHorn = 86, + VehFlyThrottleUp = 87, + VehFlyThrottleDown = 88, + VehFlyYawLeft = 89, + VehFlyYawRight = 90, + VehPassengerAimRight = 91, + VehPassengerAttack = 92, + VehSpecialAbilityFranklin = 93, + VehStuntUD = 94, + VehCinematicUD = 95, + VehCinematicUpOnly = 96, + VehCinematicDownOnly = 97, + VehCinematicLR = 98, + VehSelectNextWeapon = 99, + VehSelectPrevWeapon = 100, + VehRoof = 101, + VehJump = 102, + VehGrapplingHook = 103, + VehShuffle = 104, + VehDropProjectile = 105, + VehMouseControlOverride = 106, + VehFlyRollLR = 107, + VehFlyRollLeftOnly = 108, + VehFlyRollRightOnly = 109, + VehFlyPitchUD = 110, + VehFlyPitchUpOnly = 111, + VehFlyPitchDownOnly = 112, + VehFlyUndercarriage = 113, + VehFlyAttack = 114, + VehFlySelectNextWeapon = 115, + VehFlySelectPrevWeapon = 116, + VehFlySelectTargetLeft = 117, + VehFlySelectTargetRight = 118, + VehFlyVerticalFlightMode = 119, + VehFlyDuck = 120, + VehFlyAttackCamera = 121, + VehFlyMouseControlOverride = 122, + VehSubTurnLR = 123, + VehSubTurnLeftOnly = 124, + VehSubTurnRightOnly = 125, + VehSubPitchUD = 126, + VehSubPitchUpOnly = 127, + VehSubPitchDownOnly = 128, + VehSubThrottleUp = 129, + VehSubThrottleDown = 130, + VehSubAscend = 131, + VehSubDescend = 132, + VehSubTurnHardLeft = 133, + VehSubTurnHardRight = 134, + VehSubMouseControlOverride = 135, + VehPushbikePedal = 136, + VehPushbikeSprint = 137, + VehPushbikeFrontBrake = 138, + VehPushbikeRearBrake = 139, + MeleeAttackLight = 140, + MeleeAttackHeavy = 141, + MeleeAttackAlternate = 142, + MeleeBlock = 143, + ParachuteDeploy = 144, + ParachuteDetach = 145, + ParachuteTurnLR = 146, + ParachuteTurnLeftOnly = 147, + ParachuteTurnRightOnly = 148, + ParachutePitchUD = 149, + ParachutePitchUpOnly = 150, + ParachutePitchDownOnly = 151, + ParachuteBrakeLeft = 152, + ParachuteBrakeRight = 153, + ParachuteSmoke = 154, + ParachutePrecisionLanding = 155, + Map = 156, + SelectWeaponUnarmed = 157, + SelectWeaponMelee = 158, + SelectWeaponHandgun = 159, + SelectWeaponShotgun = 160, + SelectWeaponSMG = 161, + SelectWeaponAutoRifle = 162, + SelectWeaponSniper = 163, + SelectWeaponHeavy = 164, + SelectWeaponSpecial = 165, + SelectCharacterMichael = 166, + SelectCharacterFranklin = 167, + SelectCharacterTrevor = 168, + SelectCharacterMultiplayer = 169, + SaveReplayClip = 170, + SpecialAbilityPC = 171, + CellPhoneUp = 172, + CellPhoneDown = 173, + CellPhoneLeft = 174, + CellPhoneRight = 175, + CellPhoneSelect = 176, + CellPhoneCancel = 177, + CellPhoneOption = 178, + CellPhoneExtraOption = 179, + CellPhoneScrollForward = 180, + CellPhoneScrollBackward = 181, + CellPhoneCameraFocusLock = 182, + CellPhoneCameraGrid = 183, + CellPhoneCameraSelfie = 184, + CellPhoneCameraDOF = 185, + CellPhoneCameraExpression = 186, + FrontendDown = 187, + FrontendUp = 188, + FrontendLeft = 189, + FrontendRight = 190, + FrontendRDown = 191, + FrontendRUp = 192, + FrontendRLeft = 193, + FrontendRRight = 194, + FrontendAxisX = 195, + FrontendAxisY = 196, + FrontendRightAxisX = 197, + FrontendRightAxisY = 198, + FrontendPause = 199, + FrontendPauseAlternate = 200, + FrontendAccept = 201, + FrontendCancel = 202, + FrontendX = 203, + FrontendY = 204, + FrontendLB = 205, + FrontendRB = 206, + FrontendLT = 207, + FrontendRT = 208, + FrontendLS = 209, + FrontendRS = 210, + FrontendLeaderboard = 211, + FrontendSocialClub = 212, + FrontendSocialClubSecondary = 213, + FrontendDelete = 214, + FrontendEndscreenAccept = 215, + FrontendEndscreenExpand = 216, + FrontendSelect = 217, + ScriptLeftAxisX = 218, + ScriptLeftAxisY = 219, + ScriptRightAxisX = 220, + ScriptRightAxisY = 221, + ScriptRUp = 222, + ScriptRDown = 223, + ScriptRLeft = 224, + ScriptRRight = 225, + ScriptLB = 226, + ScriptRB = 227, + ScriptLT = 228, + ScriptRT = 229, + ScriptLS = 230, + ScriptRS = 231, + ScriptPadUp = 232, + ScriptPadDown = 233, + ScriptPadLeft = 234, + ScriptPadRight = 235, + ScriptSelect = 236, + CursorAccept = 237, + CursorCancel = 238, + CursorX = 239, + CursorY = 240, + CursorScrollUp = 241, + CursorScrollDown = 242, + EnterCheatCode = 243, + InteractionMenu = 244, + MPTextChatAll = 245, + MPTextChatTeam = 246, + MPTextChatFriends = 247, + MPTextChatCrew = 248, + PushToTalk = 249, + CreatorLs = 250, + CreatorRs = 251, + CreatorLt = 252, + CreatorRt = 253, + CreatorMenuToggle = 254, + CreatorAccept = 255, + CreatorDelete = 256, + Attack2 = 257, + RappelJump = 258, + RappelLongJump = 259, + RappelSmashWindow = 260, + PrevWeapon = 261, + NextWeapon = 262, + MeleeAttack1 = 263, + MeleeAttack2 = 264, + Whistle = 265, + MoveLeft = 266, + MoveRight = 267, + MoveUp = 268, + MoveDown = 269, + LookLeft = 270, + LookRight = 271, + LookUp = 272, + LookDown = 273, + SniperZoomIn = 274, + SniperZoomOut = 275, + SniperZoomInAlternate = 276, + SniperZoomOutAlternate = 277, + VehMoveLeft = 278, + VehMoveRight = 279, + VehMoveUp = 280, + VehMoveDown = 281, + VehGunLeft = 282, + VehGunRight = 283, + VehGunUp = 284, + VehGunDown = 285, + VehLookLeft = 286, + VehLookRight = 287, + ReplayStartStopRecording = 288, + ReplayStartStopRecordingSecondary = 289, + ScaledLookLr = 290, + ScaledLookUd = 291, + ScaledLookUpOnly = 292, + ScaledLookDownOnly = 293, + ScaledLookLeftOnly = 294, + ScaledLookRightOnly = 295, + ReplayMarkerDelete = 296, + ReplayClipDelete = 297, + ReplayPause = 298, + ReplayRewind = 299, + ReplayFfwd = 300, + ReplayNewmarker = 301, + ReplayRecord = 302, + ReplayScreenshot = 303, + ReplayHidehud = 304, + ReplayStartpoint = 305, + ReplayEndpoint = 306, + ReplayAdvance = 307, + ReplayBack = 308, + ReplayTools = 309, + ReplayRestart = 310, + ReplayShowhotkey = 311, + ReplayCyclemarkerleft = 312, + ReplayCyclemarkerright = 313, + ReplayFovincrease = 314, + ReplayFovdecrease = 315, + ReplayCameraup = 316, + ReplayCameradown = 317, + ReplaySave = 318, + ReplayToggletime = 319, + ReplayToggletips = 320, + ReplayPreview = 321, + ReplayToggleTimeline = 322, + ReplayTimelinePickupClip = 323, + ReplayTimelineDuplicateClip = 324, + ReplayTimelinePlaceClip = 325, + ReplayCtrl = 326, + ReplayTimelineSave = 327, + ReplayPreviewAudio = 328, + VehDriveLook = 329, + VehDriveLook2 = 330, + VehFlyAttack2 = 331, + RadioWheelUd = 332, + RadioWheelLr = 333, + VehicleSlowmoUd = 334, + VehSlowmoUpOnly = 335, + VehSlowmoDownOnly = 336, + VehHydraulicsControlToggle = 337, + VehHydraulicsControlLeft = 338, + VehHydraulicsControlRight = 339, + VehHydraulicsControlUp = 340, + VehHydraulicsControlDown = 341, + VehHydraulicsControlUD = 342, + VehHydraulicsControlLR = 343, + SwitchVisor = 344, + VehMeleeHold = 345, + VehMeleeLeft = 346, + VehMeleeRight = 347, + MapPOI = 348, + ReplaySnapmaticPhoto = 349, + VehCarJump = 350, + VehRocketBoost = 351, + VehFlyBoost = 352, + VehParachute = 353, + VehBikeWings = 354, + VehFlyBombBay = 355, + VehFlyCounter = 356, + VehTransform = 357 + } +} +#endif diff --git a/LemonUI/Controls.cs b/LemonUI/Controls.cs index 187aecd4..e1506506 100644 --- a/LemonUI/Controls.cs +++ b/LemonUI/Controls.cs @@ -1,6 +1,8 @@ #if FIVEM using CitizenFX.Core; using CitizenFX.Core.Native; +#elif ALTV +using AltV.Net.Client; #elif RAGEMP using RAGE.Game; #elif RPH @@ -11,6 +13,7 @@ using GTA.Native; #endif using System.Collections.Generic; +using LemonUI.Elements; namespace LemonUI { @@ -19,6 +22,8 @@ namespace LemonUI /// internal static class Controls { + #region Properties + /// /// Gets if the player used a controller for the last input. /// @@ -28,16 +33,22 @@ public static bool IsUsingController { #if FIVEM return !API.IsInputDisabled(2); +#elif ALTV + return !Alt.Natives.IsUsingKeyboardAndMouse(2); #elif RAGEMP return !Invoker.Invoke(Natives.IsInputDisabled, 2); #elif RPH return !NativeFunction.CallByHash(0xA571D46727E2B718, 2); #elif SHVDN3 - return !Function.Call(Hash._IS_USING_KEYBOARD, 2); + return !Function.Call(Hash.IS_USING_KEYBOARD_AND_MOUSE, 2); #endif } } + #endregion + + #region Functions + /// /// Checks if a control was pressed during the last frame. /// @@ -47,15 +58,18 @@ public static bool IsJustPressed(Control control) { #if FIVEM return API.IsDisabledControlJustPressed(0, (int)control); +#elif ALTV + return Alt.Natives.IsDisabledControlJustPressed(0, (int)control); #elif RAGEMP return Invoker.Invoke(Natives.IsDisabledControlJustPressed, 0, (int)control); #elif RPH return NativeFunction.CallByHash(0x91AEF906BCA88877, 0, (int)control); #elif SHVDN3 return Function.Call(Hash.IS_DISABLED_CONTROL_JUST_PRESSED, 0, (int)control); +#elif ALTV + return Alt.Natives.IsControlJustPressed((uint)control); #endif } - /// /// Checks if a control is currently pressed. /// @@ -65,6 +79,8 @@ public static bool IsPressed(Control control) { #if FIVEM return API.IsDisabledControlPressed(0, (int)control); +#elif ALTV + return Alt.Natives.IsDisabledControlPressed(0, (int)control); #elif RAGEMP return Invoker.Invoke(Natives.IsDisabledControlJustPressed, 0, (int)control); #elif RPH @@ -73,7 +89,6 @@ public static bool IsPressed(Control control) return Function.Call(Hash.IS_DISABLED_CONTROL_PRESSED, 0, (int)control); #endif } - /// /// Disables all of the controls during the next frame. /// @@ -81,6 +96,8 @@ public static void DisableAll(int inputGroup = 0) { #if FIVEM API.DisableAllControlActions(inputGroup); +#elif ALTV + Alt.Natives.DisableAllControlActions(inputGroup); #elif RAGEMP Invoker.Invoke(Natives.DisableAllControlActions, inputGroup); #elif RPH @@ -89,7 +106,6 @@ public static void DisableAll(int inputGroup = 0) Function.Call(Hash.DISABLE_ALL_CONTROL_ACTIONS, inputGroup); #endif } - /// /// Enables a control during the next frame. /// @@ -98,6 +114,8 @@ public static void EnableThisFrame(Control control) { #if FIVEM API.EnableControlAction(0, (int)control, true); +#elif ALTV + Alt.Natives.EnableControlAction(0, (int)control, true); #elif RAGEMP Invoker.Invoke(Natives.EnableControlAction, 0, (int)control, true); #elif RPH @@ -117,7 +135,6 @@ public static void EnableThisFrame(IEnumerable controls) EnableThisFrame(control); } } - /// /// Disables a control during the next frame. /// @@ -126,6 +143,8 @@ public static void DisableThisFrame(Control control) { #if FIVEM API.DisableControlAction(0, (int)control, true); +#elif ALTV + Alt.Natives.DisableControlAction(0, (int)control, true); #elif RAGEMP Invoker.Invoke(Natives.DisableControlAction, 0, (int)control, true); #elif RPH @@ -134,5 +153,7 @@ public static void DisableThisFrame(Control control) Function.Call(Hash.DISABLE_CONTROL_ACTION, 0, (int)control, true); #endif } + + #endregion } } diff --git a/LemonUI/Elements/Alignment.cs b/LemonUI/Elements/Alignment.cs index f22e59cf..a2d58eea 100644 --- a/LemonUI/Elements/Alignment.cs +++ b/LemonUI/Elements/Alignment.cs @@ -1,4 +1,4 @@ -#if RPH +#if RPH || ALTV namespace LemonUI { /// diff --git a/LemonUI/Elements/BaseElement.cs b/LemonUI/Elements/BaseElement.cs index ae9caf18..55222526 100644 --- a/LemonUI/Elements/BaseElement.cs +++ b/LemonUI/Elements/BaseElement.cs @@ -8,7 +8,7 @@ namespace LemonUI.Elements /// public abstract class BaseElement : I2Dimensional { - #region Private Fields + #region Fields /// /// The 1080 scaled position. @@ -29,7 +29,7 @@ public abstract class BaseElement : I2Dimensional #endregion - #region Public Properties + #region Properties /// /// The Position of the drawable. @@ -88,7 +88,7 @@ public BaseElement(PointF pos, SizeF size) #endregion - #region Private Functions + #region Functions /// /// Recalculates the size and position of this item. @@ -98,11 +98,6 @@ public virtual void Recalculate() relativePosition = literalPosition.ToRelative(); relativeSize = literalSize.ToRelative(); } - - #endregion - - #region Public Functions - /// /// Draws the item on the screen. /// diff --git a/LemonUI/Elements/Font.cs b/LemonUI/Elements/Font.cs index e8d12c4c..59e699f3 100644 --- a/LemonUI/Elements/Font.cs +++ b/LemonUI/Elements/Font.cs @@ -1,6 +1,6 @@ // NO MERGE -#if RPH +#if RPH || ALTV namespace LemonUI.Elements { /// diff --git a/LemonUI/Elements/I2Dimensional.cs b/LemonUI/Elements/I2Dimensional.cs index 463ef2ad..cb6ed8f3 100644 --- a/LemonUI/Elements/I2Dimensional.cs +++ b/LemonUI/Elements/I2Dimensional.cs @@ -7,6 +7,8 @@ namespace LemonUI.Elements /// public interface I2Dimensional : IRecalculable, IDrawable { + #region Properties + /// /// The Position of the drawable. /// @@ -19,5 +21,7 @@ public interface I2Dimensional : IRecalculable, IDrawable /// The Color of the drawable. /// Color Color { get; set; } + + #endregion } } diff --git a/LemonUI/Elements/IText.cs b/LemonUI/Elements/IText.cs index 7292cc96..18634e02 100644 --- a/LemonUI/Elements/IText.cs +++ b/LemonUI/Elements/IText.cs @@ -16,6 +16,8 @@ namespace LemonUI.Elements /// public interface IText : IRecalculable, IDrawable { + #region Properties + /// /// The position of the text. /// @@ -64,5 +66,7 @@ public interface IText : IRecalculable, IDrawable /// The height of each line of text. /// float LineHeight { get; } + + #endregion } } diff --git a/LemonUI/Elements/ScaledRectangle.cs b/LemonUI/Elements/ScaledRectangle.cs index 95d689bc..908432e8 100644 --- a/LemonUI/Elements/ScaledRectangle.cs +++ b/LemonUI/Elements/ScaledRectangle.cs @@ -6,6 +6,8 @@ using Rage.Native; #elif SHVDN3 using GTA.Native; +#elif ALTV +using AltV.Net.Client; #endif using System.Drawing; @@ -29,7 +31,7 @@ public ScaledRectangle(PointF pos, SizeF size) : base(pos, size) #endregion - #region Public Functions + #region Functions /// /// Draws the rectangle on the screen. @@ -44,6 +46,9 @@ public override void Draw() API.DrawRect(relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Color.R, Color.G, Color.B, Color.A); #elif RAGEMP Invoker.Invoke(Natives.DrawRect, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Color.R, Color.G, Color.B, Color.A); +#elif ALTV + Alt.Natives.DrawRect(relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Color.R, Color.G, Color.B, Color.A, + false); #elif RPH NativeFunction.CallByHash(0x3A618A217E5154F0, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Color.R, Color.G, Color.B, Color.A); #elif SHVDN3 diff --git a/LemonUI/Elements/ScaledText.cs b/LemonUI/Elements/ScaledText.cs index d734785a..d8d666ad 100644 --- a/LemonUI/Elements/ScaledText.cs +++ b/LemonUI/Elements/ScaledText.cs @@ -2,6 +2,8 @@ using CitizenFX.Core.Native; using CitizenFX.Core.UI; using Font = CitizenFX.Core.UI.Font; +#elif ALTV +using AltV.Net.Client; #elif RAGEMP using RAGE.Game; #elif RPH @@ -23,7 +25,7 @@ namespace LemonUI.Elements /// public class ScaledText : IText { - #region Consistent Values + #region Constants /// /// The size of every chunk of text. @@ -32,7 +34,7 @@ public class ScaledText : IText #endregion - #region Private Fields + #region Fields /// /// The absolute 1080p based screen position. @@ -65,7 +67,7 @@ public class ScaledText : IText #endregion - #region Public Properties + #region Properties /// /// The position of the text. @@ -149,6 +151,10 @@ public float Width API.BeginTextCommandWidth("CELL_EMAIL_BCON"); Add(); return API.EndTextCommandGetWidth(true) * 1f.ToXAbsolute(); +#elif ALTV + Alt.Natives.BeginTextCommandGetScreenWidthOfDisplayText("CELL_EMAIL_BCON"); + Add(); + return Alt.Natives.EndTextCommandGetScreenWidthOfDisplayText(true) * 1f.ToXAbsolute(); #elif RAGEMP Invoker.Invoke(Natives.BeginTextCommandWidth, "CELL_EMAIL_BCON"); Add(); @@ -158,9 +164,9 @@ public float Width Add(); return NativeFunction.CallByHash(0x85F061DA64ED2F67, true) * 1f.ToXAbsolute(); #elif SHVDN3 - Function.Call(Hash._BEGIN_TEXT_COMMAND_GET_WIDTH, "CELL_EMAIL_BCON"); + Function.Call(Hash.BEGIN_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT, "CELL_EMAIL_BCON"); Add(); - return Function.Call(Hash._END_TEXT_COMMAND_GET_WIDTH, true) * 1f.ToXAbsolute(); + return Function.Call(Hash.END_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT, true) * 1f.ToXAbsolute(); #endif } } @@ -173,22 +179,26 @@ public int LineCount { #if FIVEM API.BeginTextCommandLineCount("CELL_EMAIL_BCON"); +#elif ALTV + Alt.Natives.BeginTextCommandGetNumberOfLinesForString("CELL_EMAIL_BCON"); #elif RAGEMP Invoker.Invoke(Natives.BeginTextCommandLineCount, "CELL_EMAIL_BCON"); #elif RPH NativeFunction.CallByHash(0x521FB041D93DD0E4, "CELL_EMAIL_BCON"); #elif SHVDN3 - Function.Call(Hash._BEGIN_TEXT_COMMAND_LINE_COUNT, "CELL_EMAIL_BCON"); + Function.Call(Hash.BEGIN_TEXT_COMMAND_GET_NUMBER_OF_LINES_FOR_STRING, "CELL_EMAIL_BCON"); #endif Add(); #if FIVEM return API.EndTextCommandGetLineCount(relativePosition.X, relativePosition.Y); +#elif ALTV + return Alt.Natives.EndTextCommandGetNumberOfLinesForString(relativePosition.X, relativePosition.Y); #elif RAGEMP return Invoker.Invoke(Natives.EndTextCommandGetLineCount, relativePosition.X, relativePosition.Y); #elif RPH return NativeFunction.CallByHash(0x9040DFB09BE75706, relativePosition.X, relativePosition.Y); #elif SHVDN3 - return Function.Call(Hash._END_TEXT_COMMAND_LINE_COUNT, relativePosition.X, relativePosition.Y); + return Function.Call(Hash.END_TEXT_COMMAND_GET_NUMBER_OF_LINES_FOR_STRING, relativePosition.X, relativePosition.Y); #endif } } @@ -202,6 +212,8 @@ public float LineHeight // Height will always be 1080 #if FIVEM return 1080 * API.GetTextScaleHeight(Scale, (int)Font); +#elif ALTV + return 1080 * Alt.Natives.GetRenderedCharacterHeight(Scale, (int)Font); #elif RAGEMP return 1080 * Invoker.Invoke(Natives.GetTextScaleHeight, Scale, (int)Font); #elif RPH @@ -299,6 +311,42 @@ private void Add() { API.SetTextWrap(0f, relativePosition.X); } +#elif ALTV + foreach (var chunk in chunks) + { + Alt.Natives.AddTextComponentSubstringPlayerName(chunk); + } + Alt.Natives.SetTextFont((int)Font); + Alt.Natives.SetTextScale(1f, Scale); + Alt.Natives.SetTextColour(Color.R, Color.G, Color.B, Color.A); + Alt.Natives.SetTextJustification((int)Alignment); + if (Shadow) + { + Alt.Natives.SetTextDropShadow(); + } + if (Outline) + { + Alt.Natives.SetTextOutline(); + } + if (WordWrap > 0) + { + switch (Alignment) + { + case Alignment.Center: + Alt.Natives.SetTextWrap(relativePosition.X - (realWrap * 0.5f), relativePosition.X + (realWrap * 0.5f)); + break; + case Alignment.Left: + Alt.Natives.SetTextWrap(relativePosition.X, relativePosition.X + realWrap); + break; + case Alignment.Right: + Alt.Natives.SetTextWrap(relativePosition.X - realWrap, relativePosition.X); + break; + } + } + else if (Alignment == Alignment.Right) + { + Alt.Natives.SetTextWrap(0f, relativePosition.X); + } #elif RAGEMP foreach (string chunk in chunks) { @@ -471,7 +519,7 @@ public void Recalculate() #endregion - #region Public Functions + #region Functions /// /// Draws the text on the screen. @@ -480,6 +528,8 @@ public void Draw() { #if FIVEM API.SetTextEntry("CELL_EMAIL_BCON"); +#elif ALTV + Alt.Natives.BeginTextCommandDisplayText("CELL_EMAIL_BCON"); #elif RAGEMP Invoker.Invoke(Natives.BeginTextCommandDisplayText, "CELL_EMAIL_BCON"); #elif RPH @@ -492,6 +542,8 @@ public void Draw() #if FIVEM API.DrawText(relativePosition.X, relativePosition.Y); +#elif ALTV + Alt.Natives.EndTextCommandDisplayText(relativePosition.X, relativePosition.Y, 0); #elif RAGEMP Invoker.Invoke(Natives.EndTextCommandDisplayText, relativePosition.X, relativePosition.Y); #elif RPH diff --git a/LemonUI/Elements/ScaledTexture.cs b/LemonUI/Elements/ScaledTexture.cs index d6339d01..67870416 100644 --- a/LemonUI/Elements/ScaledTexture.cs +++ b/LemonUI/Elements/ScaledTexture.cs @@ -6,6 +6,8 @@ using Rage.Native; #elif SHVDN3 using GTA.Native; +#elif ALTV +using AltV.Net.Client; #endif using System.Drawing; @@ -16,7 +18,7 @@ namespace LemonUI.Elements /// public class ScaledTexture : BaseElement { - #region Public Properties + #region Properties /// /// The dictionary where the texture is loaded. @@ -55,7 +57,7 @@ public ScaledTexture(PointF pos, SizeF size, string dictionary, string texture) #endregion - #region Private Functions + #region Tools /// /// Requests the texture dictionary for this class. @@ -72,6 +74,11 @@ private void Request() { Invoker.Invoke(Natives.RequestStreamedTextureDict, Dictionary, true); } +#elif ALTV + if (!Alt.Natives.HasStreamedTextureDictLoaded(Dictionary)) + { + Alt.Natives.RequestStreamedTextureDict(Dictionary, true); + } #elif RPH if (!NativeFunction.CallByHash(0x0145F696AAAAD2E4, Dictionary)) { @@ -87,7 +94,7 @@ private void Request() #endregion - #region Public Functions + #region Functions /// /// Draws the texture on the screen. @@ -105,6 +112,8 @@ public override void Draw() Invoker.Invoke(Natives.DrawSprite, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Heading, Color.R, Color.G, Color.B, Color.A); #elif RPH NativeFunction.CallByHash(0xE7FFAE5EBF23D890, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Heading, Color.R, Color.G, Color.B, Color.A); +#elif ALTV + Alt.Natives.DrawSprite(Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Heading, Color.R, Color.G, Color.B, Color.A, false, 0); #elif SHVDN3 Function.Call(Hash.DRAW_SPRITE, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, Heading, Color.R, Color.G, Color.B, Color.A); #endif @@ -125,6 +134,8 @@ public void DrawSpecific(PointF topLeft, PointF bottomRight) Invoker.Invoke(0x95812F9B26074726, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y, Heading, Color.R, Color.G, Color.B, Color.A); #elif RPH NativeFunction.CallByHash(0x95812F9B26074726, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y, Heading, Color.R, Color.G, Color.B, Color.A); +#elif ALTV + Alt.Natives.DrawSpriteArxWithUv(Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y, Heading, Color.R, Color.G, Color.B, Color.A, 0); #elif SHVDN3 Function.Call((Hash)0x95812F9B26074726, Dictionary, Texture, relativePosition.X, relativePosition.Y, relativeSize.Width, relativeSize.Height, topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y, Heading, Color.R, Color.G, Color.B, Color.A); #endif diff --git a/LemonUI/Extensions/Float.cs b/LemonUI/Extensions/FloatExtensions.cs similarity index 97% rename from LemonUI/Extensions/Float.cs rename to LemonUI/Extensions/FloatExtensions.cs index 41c738fe..81bb74e6 100644 --- a/LemonUI/Extensions/Float.cs +++ b/LemonUI/Extensions/FloatExtensions.cs @@ -5,6 +5,8 @@ namespace LemonUI.Extensions /// public static class FloatExtensions { + #region Extensions + /// /// Converts an absolute X or Width float to a relative one. /// @@ -45,5 +47,7 @@ public static float ToYAbsolute(this float fin) Screen.ToAbsolute(0, fin, out _, out float fout); return fout; } + + #endregion } } diff --git a/LemonUI/Extensions/Point.cs b/LemonUI/Extensions/PointExtensions.cs similarity index 95% rename from LemonUI/Extensions/Point.cs rename to LemonUI/Extensions/PointExtensions.cs index 634b114e..5b81adf5 100644 --- a/LemonUI/Extensions/Point.cs +++ b/LemonUI/Extensions/PointExtensions.cs @@ -7,6 +7,8 @@ namespace LemonUI.Extensions /// public static class PointExtensions { + #region Extensions + /// /// Converts an absolute 1080-based position into a relative one. /// @@ -27,5 +29,7 @@ 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 } } diff --git a/LemonUI/Extensions/Size.cs b/LemonUI/Extensions/SizeExtensions.cs similarity index 95% rename from LemonUI/Extensions/Size.cs rename to LemonUI/Extensions/SizeExtensions.cs index 254c330c..e2a893e1 100644 --- a/LemonUI/Extensions/Size.cs +++ b/LemonUI/Extensions/SizeExtensions.cs @@ -7,6 +7,8 @@ namespace LemonUI.Extensions /// public static class SizeExtensions { + #region Extensions + /// /// Converts an absolute 1080-based size into a relative one. /// @@ -27,5 +29,7 @@ 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 } } diff --git a/LemonUI/GFXAlignment.cs b/LemonUI/GFXAlignment.cs new file mode 100644 index 00000000..62190bdf --- /dev/null +++ b/LemonUI/GFXAlignment.cs @@ -0,0 +1,29 @@ +namespace LemonUI +{ + /// + /// Represents the internal alignment of screen elements. + /// + public enum GFXAlignment + { + /// + /// Vertical Alignment to the Bottom. + /// + Bottom = 66, + /// + /// Vertical Alignment to the Top. + /// + Top = 84, + /// + /// Centered Vertically or Horizontally. + /// + Center = 67, + /// + /// Horizontal Alignment to the Left. + /// + Left = 76, + /// + /// Horizontal Alignment to the Right. + /// + Right = 82, + } +} diff --git a/LemonUI/IContainer.cs b/LemonUI/IContainer.cs index c2323c40..6f4fc393 100644 --- a/LemonUI/IContainer.cs +++ b/LemonUI/IContainer.cs @@ -8,6 +8,8 @@ namespace LemonUI /// The type of Element that this container handles. public interface IContainer : IRecalculable, IProcessable { + #region Functions + /// /// Adds the specified item into the Container. /// @@ -33,5 +35,7 @@ public interface IContainer : IRecalculable, IProcessable /// The item to check. /// if the item is in this container, otherwise. bool Contains(T item); + + #endregion } } diff --git a/LemonUI/IDrawable.cs b/LemonUI/IDrawable.cs index 7ae453f8..56a8465e 100644 --- a/LemonUI/IDrawable.cs +++ b/LemonUI/IDrawable.cs @@ -5,9 +5,13 @@ namespace LemonUI /// public interface IDrawable { + #region Functions + /// /// Draws the item on the screen. /// void Draw(); + + #endregion } } diff --git a/LemonUI/IProcessable.cs b/LemonUI/IProcessable.cs index ca01c2a1..acef97f7 100644 --- a/LemonUI/IProcessable.cs +++ b/LemonUI/IProcessable.cs @@ -5,13 +5,22 @@ namespace LemonUI /// public interface IProcessable { + #region Properties + /// /// If this processable item is visible on the screen. /// bool Visible { get; set; } + + #endregion + + #region Functions + /// /// Processes the object. /// void Process(); + + #endregion } } diff --git a/LemonUI/IRecalculable.cs b/LemonUI/IRecalculable.cs index 3012adb2..8cfe4193 100644 --- a/LemonUI/IRecalculable.cs +++ b/LemonUI/IRecalculable.cs @@ -5,9 +5,13 @@ namespace LemonUI /// public interface IRecalculable { + #region Functions + /// /// Recalculates the values. /// void Recalculate(); + + #endregion } } diff --git a/LemonUI/Menus/BadgeSet.cs b/LemonUI/Menus/BadgeSet.cs index 90033c16..5566f4a2 100644 --- a/LemonUI/Menus/BadgeSet.cs +++ b/LemonUI/Menus/BadgeSet.cs @@ -26,7 +26,7 @@ public class BadgeSet #endregion - #region Constructor + #region Constructors /// /// Creates a new empty . diff --git a/LemonUI/Menus/GridValueChangedArgs.cs b/LemonUI/Menus/GridValueChangedArgs.cs index 2e907e93..1b5f4f20 100644 --- a/LemonUI/Menus/GridValueChangedArgs.cs +++ b/LemonUI/Menus/GridValueChangedArgs.cs @@ -7,6 +7,8 @@ namespace LemonUI.Menus /// public class GridValueChangedArgs { + #region Properties + /// /// The values present before they were changed. /// @@ -16,10 +18,16 @@ public class GridValueChangedArgs /// public PointF After { get; } + #endregion + + #region Constructors + internal GridValueChangedArgs(PointF before, PointF after) { Before = before; After = after; } + + #endregion } } diff --git a/LemonUI/Menus/HeaderBehavior.cs b/LemonUI/Menus/HeaderBehavior.cs new file mode 100644 index 00000000..8562bb7a --- /dev/null +++ b/LemonUI/Menus/HeaderBehavior.cs @@ -0,0 +1,21 @@ +namespace LemonUI.Menus +{ + /// + /// The behavior of the 's header. + /// + public enum HeaderBehavior + { + /// + /// The header will always be shown. + /// + AlwaysShow = 0, + /// + /// The header will always be shown, except when is empty. + /// + ShowIfRequired = 1, + /// + /// The header will never be shown. + /// + AlwaysHide = 2 + } +} diff --git a/LemonUI/Menus/ItemActivatedArgs.cs b/LemonUI/Menus/ItemActivatedArgs.cs index d3b90421..5a3bf21b 100644 --- a/LemonUI/Menus/ItemActivatedArgs.cs +++ b/LemonUI/Menus/ItemActivatedArgs.cs @@ -5,14 +5,22 @@ /// public class ItemActivatedArgs { + #region Properties + /// /// The item that was just activated. /// public NativeItem Item { get; } + #endregion + + #region Constructors + internal ItemActivatedArgs(NativeItem item) { Item = item; } + + #endregion } } diff --git a/LemonUI/Menus/ItemChangedEventArgs.cs b/LemonUI/Menus/ItemChangedEventArgs.cs index 06ba840d..4b9963b3 100644 --- a/LemonUI/Menus/ItemChangedEventArgs.cs +++ b/LemonUI/Menus/ItemChangedEventArgs.cs @@ -6,6 +6,8 @@ /// The type of object that got changed. public class ItemChangedEventArgs { + #region Properties + /// /// The new object. /// @@ -19,11 +21,17 @@ public class ItemChangedEventArgs /// public Direction Direction { get; } + #endregion + + #region Constructors + internal ItemChangedEventArgs(T obj, int index, Direction direction) { Object = obj; Index = index; Direction = direction; } + + #endregion } } diff --git a/LemonUI/Menus/MenuModifiedEventArgs.cs b/LemonUI/Menus/MenuModifiedEventArgs.cs index 7211911c..d4be4c27 100644 --- a/LemonUI/Menus/MenuModifiedEventArgs.cs +++ b/LemonUI/Menus/MenuModifiedEventArgs.cs @@ -33,4 +33,4 @@ public MenuModifiedEventArgs(NativeItem item, ItemOperation operation) #endregion } -} \ No newline at end of file +} diff --git a/LemonUI/Menus/NativeCheckboxItem.cs b/LemonUI/Menus/NativeCheckboxItem.cs index 6a4f2b27..2691d090 100644 --- a/LemonUI/Menus/NativeCheckboxItem.cs +++ b/LemonUI/Menus/NativeCheckboxItem.cs @@ -14,7 +14,7 @@ public class NativeCheckboxItem : NativeItem /// /// The image shown on the checkbox. /// - internal protected ScaledTexture check = new ScaledTexture(PointF.Empty, SizeF.Empty, "commonmenu", string.Empty); + protected internal ScaledTexture check = new ScaledTexture(PointF.Empty, SizeF.Empty, "commonmenu", string.Empty); /// /// If this item is checked or not. /// @@ -22,6 +22,31 @@ public class NativeCheckboxItem : NativeItem #endregion + #region Defaults + + /// + /// The default checkbox textures when the checkbox is checked. + /// + public static readonly BadgeSet DefaultCheckedSet = new BadgeSet + { + NormalDictionary = "commonmenu", + NormalTexture = "shop_box_tick", + HoveredDictionary = "commonmenu", + HoveredTexture = "shop_box_tickb" + }; + /// + /// The default checkbox textures when the checkbox is not checked. + /// + public static readonly BadgeSet DefaultUncheckedSet = new BadgeSet + { + NormalDictionary = "commonmenu", + NormalTexture = "shop_box_blank", + HoveredDictionary = "commonmenu", + HoveredTexture = "shop_box_blankb" + }; + + #endregion + #region Properties /// @@ -41,6 +66,14 @@ public bool Checked CheckboxChanged?.Invoke(this, EventArgs.Empty); } } + /// + /// The textures used when the checkbox is checked. + /// + public BadgeSet CheckedSet { get; set; } = DefaultCheckedSet; + /// + /// The textures used when the checkbox is unchecked. + /// + public BadgeSet UncheckedSet { get; set; } = DefaultUncheckedSet; #endregion @@ -93,13 +126,13 @@ public NativeCheckboxItem(string title, string description, bool check) : base(t #endregion - #region Local Events + #region Event Functions private void NativeCheckboxItem_EnabledChanged(object sender, EventArgs e) => UpdateTexture(lastSelected); #endregion - #region Internal Functions + #region Tools /// /// Inverts the checkbox activation. @@ -108,23 +141,25 @@ public NativeCheckboxItem(string title, string description, bool check) : base(t /// /// Updates the texture of the sprite. /// - internal protected void UpdateTexture(bool selected) + protected internal void UpdateTexture(bool selected) { + bool showLight = !selected || !Enabled; + // If the item is not selected or is not enabled, use the white pictures - if (!selected || !Enabled) + if (Checked) { - check.Texture = Checked ? "shop_box_tick" : "shop_box_blank"; + check.Texture = showLight ? CheckedSet.NormalTexture : CheckedSet.HoveredTexture; } // Otherwise, use the black ones else { - check.Texture = Checked ? "shop_box_tickb" : "shop_box_blankb"; + check.Texture = showLight ? UncheckedSet.NormalTexture : UncheckedSet.HoveredTexture; } } #endregion - #region Public Functions + #region Functions /// /// Recalculates the item positions and sizes with the specified values. diff --git a/LemonUI/Menus/NativeColorData.cs b/LemonUI/Menus/NativeColorData.cs index 63d8a4a6..d032135f 100644 --- a/LemonUI/Menus/NativeColorData.cs +++ b/LemonUI/Menus/NativeColorData.cs @@ -8,13 +8,13 @@ namespace LemonUI.Menus /// public class NativeColorData { - #region Internal Fields + #region Fields internal readonly ScaledRectangle rectangle = new ScaledRectangle(PointF.Empty, SizeF.Empty); #endregion - #region Public Properties + #region Properties /// /// The name of the color. @@ -31,7 +31,7 @@ public Color Color #endregion - #region Constructor + #region Constructors /// /// Creates a new Color Panel information. diff --git a/LemonUI/Menus/NativeColorPanel.cs b/LemonUI/Menus/NativeColorPanel.cs index be024211..0da349ab 100644 --- a/LemonUI/Menus/NativeColorPanel.cs +++ b/LemonUI/Menus/NativeColorPanel.cs @@ -1,6 +1,8 @@ #if FIVEM using CitizenFX.Core; using CitizenFX.Core.UI; +#elif ALTV +using AltV.Net.Client; #elif RAGEMP using RAGE.Game; #elif RPH @@ -22,12 +24,14 @@ namespace LemonUI.Menus /// public class NativeColorPanel : NativePanel, IEnumerable { + #region Constants /// /// The space difference for the colors and opacity bar on the left. /// private const float leftDifference = 16; + /// /// The space difference for the colors and opacity bar on the left. /// @@ -35,16 +39,18 @@ public class NativeColorPanel : NativePanel, IEnumerable #endregion - #region Private Fields + #region Fields /// /// The position reported after the last Recalculation. /// private PointF lastPosition = PointF.Empty; + /// /// The Width reported after the last Recalculation. /// private float lastWidth = 0; + /// /// The title of the Color Panel. /// @@ -52,10 +58,12 @@ public class NativeColorPanel : NativePanel, IEnumerable { Alignment = Alignment.Center }; + /// /// The rectangle used for marking the item selection on the screen. /// private ScaledRectangle selectionRectangle = new ScaledRectangle(PointF.Empty, SizeF.Empty); + /// /// The "Opacity" text when the opacity bar is enabled /// @@ -63,14 +71,17 @@ public class NativeColorPanel : NativePanel, IEnumerable { Alignment = Alignment.Center }; + /// /// The zero percent text when the opacity bar is enabled. /// private ScaledText percentMin = new ScaledText(PointF.Empty, "0%", 0.325f); + /// /// The 100 percent text when the opacity bar is enabled. /// private ScaledText percentMax = new ScaledText(PointF.Empty, "100%", 0.325f); + /// /// The top section of the opacity bar. /// @@ -78,6 +89,7 @@ public class NativeColorPanel : NativePanel, IEnumerable { Color = Color.FromArgb(255, 240, 240, 240) }; + /// /// The background of the opacity bar. /// @@ -85,47 +97,52 @@ public class NativeColorPanel : NativePanel, IEnumerable { Color = Color.FromArgb(150, 88, 88, 88) }; + /// /// If the opacity bar is available to the user. /// private bool showOpacity = false; + /// /// The current value of the opacity slider. /// private int opacity = 0; + /// /// The current index of the Colors. /// private int index = 0; + /// /// The position of the first item. /// private int firstItem = 0; + /// /// The maximum number of items shown at once. /// private int maxItems = 9; + /// /// The generic title for this color. /// private string simpleTitle = "Color"; + /// /// The style of the title. /// private ColorTitleStyle titleStyle = ColorTitleStyle.Simple; + /// /// If the number of colors should be shown. /// private bool showCount = true; + /// /// The items that are currently visible on the screen. /// private List visibleItems = new List(); - #endregion - - #region Public Fields - /// /// The default sound used for the Color Navigation. /// @@ -133,10 +150,11 @@ public class NativeColorPanel : NativePanel, IEnumerable #endregion - #region Public Properties + #region Properties /// public override bool Clickable => true; + /// /// If the Opacity selector should be shown. /// @@ -149,6 +167,7 @@ public bool ShowOpacity Recalculate(); } } + /// /// The opacity value of the color. /// @@ -164,6 +183,7 @@ public int Opacity { return -1; } + return opacity; } set @@ -172,14 +192,17 @@ public int Opacity { return; } + if (value > 100 || value < 0) { throw new IndexOutOfRangeException("The value needs to be over 0 and under 100."); } + opacity = value; UpdateOpacityBar(); } } + /// /// The currently selected color. /// @@ -192,14 +215,17 @@ public Color SelectedColor { // If there is no selected color information, return NativeColorData data = SelectedItem; + if (data == null) { return default; } + // Otherwise, return the color return Color.FromArgb(ShowOpacity ? (int)(255 * (Opacity * 0.01f)) : 255, data.Color.R, data.Color.G, data.Color.B); } } + /// /// Returns the currently selected . /// @@ -211,9 +237,11 @@ public NativeColorData SelectedItem { return null; } + return Colors[SelectedIndex]; } } + /// /// The index of the currently selected Color. /// @@ -225,6 +253,7 @@ public int SelectedIndex { return -1; } + return index; } set @@ -281,6 +310,7 @@ public int SelectedIndex Sound?.PlayFrontend(); } } + /// /// The Title used for the Panel when is set to . /// @@ -293,6 +323,7 @@ public string Title UpdateTitle(); } } + /// /// The style of the Panel Title. /// @@ -305,6 +336,7 @@ public ColorTitleStyle TitleStyle UpdateTitle(); } } + /// /// If the count of items should be shown as part of the title. /// @@ -317,6 +349,7 @@ public bool ShowCount UpdateTitle(); } } + /// /// THe maximum number of items shown on the screen. /// @@ -329,11 +362,13 @@ public int MaxItems { return; } + maxItems = value; UpdateItems(); UpdateTitle(); } } + /// /// The colors shown on this Panel. /// @@ -353,6 +388,7 @@ public int MaxItems public NativeColorPanel() : this(string.Empty) { } + /// /// Creates a Panel with a specific Title and set of Colors. /// @@ -368,7 +404,7 @@ public NativeColorPanel(string title, params NativeColorData[] colors) #endregion - #region Private Functions + #region Tools /// /// Updates the Text of the Title. @@ -382,9 +418,11 @@ private void UpdateTitle() { case ColorTitleStyle.Simple: newTitle = Title; + break; case ColorTitleStyle.ColorName: newTitle = SelectedItem == null ? string.Empty : SelectedItem.Name; + break; } @@ -404,6 +442,7 @@ private void UpdateTitle() // And finally set the new title title.Text = newTitle; } + /// /// Updates the position of the Items. /// @@ -458,6 +497,7 @@ private void UpdateItems() // Finally, update the text of the title UpdateTitle(); } + /// /// Updates the size of the opacity bar. /// @@ -479,6 +519,7 @@ private void UpdateOpacityBar() opacityForeground.Position = new PointF(x, y); opacityForeground.Size = new SizeF(width * (Opacity * 0.01f), height); } + /// /// Recalculates the Color panel with the last known Position and Width. /// @@ -486,12 +527,14 @@ private void UpdateOpacityBar() #endregion - #region Public Functions + #region Functions /// public IEnumerator GetEnumerator() => Colors.GetEnumerator(); + /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + /// /// Moves to the Previous Color. /// @@ -514,6 +557,7 @@ public void Previous() SelectedIndex -= 1; } } + /// /// Moves to the Next Color. /// @@ -536,6 +580,7 @@ public void Next() SelectedIndex += 1; } } + /// /// Adds a color to the Panel. /// @@ -546,9 +591,11 @@ public void Add(NativeColorData color) { throw new ArgumentException("Color is already part of the Panel.", nameof(color)); } + Colors.Add(color); Recalculate(); } + /// /// Removes a color from the panel. /// @@ -558,6 +605,7 @@ public void Remove(NativeColorData color) // Remove it if there // If not, ignore it Colors.Remove(color); + // If the index is higher or equal than the max number of items // Set the max - 1 if (SelectedIndex >= Colors.Count) @@ -569,6 +617,7 @@ public void Remove(NativeColorData color) UpdateItems(); } } + /// /// Removes all of the /// @@ -584,8 +633,10 @@ public void Remove(Func func) Colors.Remove(color); } } + Recalculate(); } + /// /// Removes all of the colors from the Panel. /// @@ -594,11 +645,13 @@ public void Clear() Colors.Clear(); Recalculate(); } + /// /// Checks if the Color Data is present on this Panel. /// /// The Color Data to check. public void Contains(NativeColorData color) => Colors.Contains(color); + /// /// Recalculates the position of the Color Panel. /// @@ -627,22 +680,35 @@ public override void Recalculate(PointF position, float width) // Finally, update the list of items UpdateItems(); } + /// /// Draws the Color Panel. /// public override void Process() { // If the user pressed one of the keys, move to the left or right - if (Controls.IsJustPressed(Control.FrontendLt)) +#if ALTV + if (Controls.IsJustPressed(Control.FrontendLT)) +#else + if (Controls.IsJustPressed(Control.FrontendLt)) +#endif { Previous(); } +#if ALTV + else if (Controls.IsJustPressed(Control.FrontendRT)) +#else else if (Controls.IsJustPressed(Control.FrontendRt)) +#endif { Next(); } // If the user pressed one of the bumpers with the Opacity bar enabled, increase or decrease it +#if ALTV + else if (ShowOpacity && Controls.IsJustPressed(Control.FrontendLB)) +#else else if (ShowOpacity && Controls.IsJustPressed(Control.FrontendLb)) +#endif { if (Opacity > 0) { @@ -650,7 +716,11 @@ public override void Process() Sound?.PlayFrontend(); } } +#if ALTV + else if (ShowOpacity && Controls.IsJustPressed(Control.FrontendRB)) +#else else if (ShowOpacity && Controls.IsJustPressed(Control.FrontendRb)) +#endif { if (Opacity < 100) { @@ -662,14 +732,17 @@ public override void Process() // Draw the items base.Process(); title.Draw(); + foreach (NativeColorData color in visibleItems) { color.rectangle.Draw(); } + if (Colors.Count != 0) { selectionRectangle.Draw(); } + if (ShowOpacity) { opacityText.Draw(); @@ -681,5 +754,6 @@ public override void Process() } #endregion + } -} +} \ No newline at end of file diff --git a/LemonUI/Menus/NativeDynamicItem.cs b/LemonUI/Menus/NativeDynamicItem.cs index 1e962d02..1f4666c4 100644 --- a/LemonUI/Menus/NativeDynamicItem.cs +++ b/LemonUI/Menus/NativeDynamicItem.cs @@ -27,6 +27,7 @@ public T SelectedItem set { item = value; + UpdateItemName(); } } @@ -41,7 +42,7 @@ public T SelectedItem #endregion - #region Constructor + #region Constructors /// /// Creates a new Dynamic List Item. diff --git a/LemonUI/Menus/NativeGridPanel.cs b/LemonUI/Menus/NativeGridPanel.cs index ab8f2cb3..0408f755 100644 --- a/LemonUI/Menus/NativeGridPanel.cs +++ b/LemonUI/Menus/NativeGridPanel.cs @@ -2,6 +2,8 @@ using CitizenFX.Core; using CitizenFX.Core.Native; using CitizenFX.Core.UI; +#elif ALTV +using AltV.Net.Client; #elif RAGEMP using RAGE.Game; #elif RPH @@ -190,7 +192,7 @@ public GridStyle Style #endregion - #region Constructor + #region Constructors /// /// Creates a new . @@ -306,8 +308,13 @@ public override void Process() } else { +#if ALTV + Controls.DisableThisFrame(Control.LookUd); + Controls.DisableThisFrame(Control.LookLr); +#else Controls.DisableThisFrame(Control.LookUpDown); Controls.DisableThisFrame(Control.LookLeftRight); +#endif Controls.EnableThisFrame(Control.ScriptRightAxisX); Controls.EnableThisFrame(Control.ScriptRightAxisY); @@ -315,6 +322,10 @@ public override void Process() float rX = Game.GetControlNormal(0, Control.ScriptRightAxisX); float rY = Game.GetControlNormal(0, Control.ScriptRightAxisY); float frameTime = Game.LastFrameTime; +#elif ALTV + float rX = Alt.Natives.GetControlNormal(0, (int)Control.ScriptRightAxisX); + float rY = Alt.Natives.GetControlNormal(0, (int)Control.ScriptRightAxisY); + float frameTime = Alt.Natives.GetFrameTime(); #elif RAGEMP float rX = Invoker.Invoke(0xEC3C9B8D5327B563, 0, (int)Control.ScriptRightAxisX); float rY = Invoker.Invoke(0xEC3C9B8D5327B563, 0, (int)Control.ScriptRightAxisY); diff --git a/LemonUI/Menus/NativeItem.cs b/LemonUI/Menus/NativeItem.cs index 248a7686..9dcf92bc 100644 --- a/LemonUI/Menus/NativeItem.cs +++ b/LemonUI/Menus/NativeItem.cs @@ -19,7 +19,7 @@ namespace LemonUI.Menus /// public class NativeItem : IDrawable { - #region Protected Internal Fields + #region Fields /// /// The title of the object. @@ -50,10 +50,6 @@ public class NativeItem : IDrawable /// protected internal ScaledText altTitle; - #endregion - - #region Private Fields - private bool enabled = true; private BadgeSet badgeSetLeft; private BadgeSet badgeSetRight; @@ -62,7 +58,7 @@ public class NativeItem : IDrawable #endregion - #region Public Properties + #region Properties /// /// If this item can be used or not. @@ -287,7 +283,7 @@ public NativeItem(string title, string description, string altTitle) #endregion - #region Event Triggers + #region Tools /// /// Triggers the Selected event. @@ -301,10 +297,6 @@ public NativeItem(string title, string description, string altTitle) /// The source of the event. protected internal void OnActivated(object sender) => Activated?.Invoke(sender, EventArgs.Empty); - #endregion - - #region Private Functions - /// /// Recalculates the item with the last known values. /// @@ -312,7 +304,7 @@ public NativeItem(string title, string description, string altTitle) #endregion - #region Public Functions + #region Functions /// /// Recalculates the item positions and sizes with the specified values. diff --git a/LemonUI/Menus/NativeListItem.cs b/LemonUI/Menus/NativeListItem.cs index b2c803be..93ab31f8 100644 --- a/LemonUI/Menus/NativeListItem.cs +++ b/LemonUI/Menus/NativeListItem.cs @@ -1,7 +1,4 @@ using LemonUI.Elements; -using System; -using System.Collections; -using System.Collections.Generic; using System.Drawing; namespace LemonUI.Menus @@ -10,360 +7,26 @@ namespace LemonUI.Menus /// Base class for list items. /// public abstract class NativeListItem : NativeSlidableItem - { - /// - /// The text of the current item. - /// - internal protected ScaledText text = null; - - /// - /// Creates a new list item with a title and subtitle. - /// - /// The title of the Item. - /// The subtitle of the Item. - public NativeListItem(string title, string subtitle) : base(title, subtitle) - { - text = new ScaledText(PointF.Empty, string.Empty, 0.35f); - } - } - - /// - /// An item that allows you to scroll between a set of objects. - /// - public class NativeListItem : NativeListItem, IEnumerable { #region Fields - private int index = 0; - private List items = new List(); - - #endregion - - #region Properties - /// - /// The index of the currently selected index. - /// - public int SelectedIndex - { - get - { - if (Items.Count == 0) - { - return -1; - } - return index; - } - set - { - if (Items.Count == 0) - { - throw new InvalidOperationException("There are no available items."); - } - if (value < 0) - { - throw new InvalidOperationException("The index is under zero."); - } - if (value >= Items.Count) - { - throw new InvalidOperationException($"The index is over the limit of {Items.Count - 1}"); - } - if (index == value) - { - return; - } - index = value; - TriggerEvent(value, Direction.Unknown); - UpdateIndex(); - } - } - /// - /// The currently selected item. - /// - public T SelectedItem - { - get - { - if (Items.Count == 0) - { - return default; - } - - return Items[SelectedIndex]; - } - set - { - if (Items.Count == 0) - { - throw new InvalidOperationException("There are no available items."); - } - - int newIndex = Items.IndexOf(value); - - if (newIndex == -1) - { - throw new InvalidOperationException("The object is not the list of Items."); - } - - SelectedIndex = newIndex; - } - } - /// - /// The objects used by this item. - /// - public List Items - { - get => items; - set - { - items = value; - UpdateIndex(); - } - } - - #endregion - - #region Events - - /// - /// Event triggered when the selected item is changed. + /// The text of the current item. /// - public event ItemChangedEventHandler ItemChanged; + protected internal ScaledText text = null; #endregion #region Constructors /// - /// Creates a new . - /// - /// The title of the Item. - /// The objects that are available on the Item. - public NativeListItem(string title, params T[] objs) : this(title, string.Empty, objs) - { - } - /// - /// Creates a new . + /// Creates a new list item with a title and subtitle. /// /// The title of the Item. /// The subtitle of the Item. - /// The objects that are available on the Item. - public NativeListItem(string title, string subtitle, params T[] objs) : base(title, subtitle) - { - items = new List(); - items.AddRange(objs); - UpdateIndex(); - } - - #endregion - - #region Tools - - /// - /// Triggers the event. - /// - private void TriggerEvent(int index, Direction direction) - { - ItemChanged?.Invoke(this, new ItemChangedEventArgs(items[index], index, direction)); - } - private void FixIndexIfRequired() - { - if (index >= items.Count) - { - index = items.Count - 1; - UpdateIndex(); - } - } - /// - /// Updates the currently selected item based on the index. - /// - private void UpdateIndex() - { - text.Text = SelectedIndex != -1 ? SelectedItem.ToString() : string.Empty; - - text.Position = new PointF(RightArrow.Position.X - text.Width + 3, text.Position.Y); - LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, LeftArrow.Position.Y); - } - - #endregion - - #region Functions - - /// - public IEnumerator GetEnumerator() => Items.GetEnumerator(); - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - /// - /// Adds a into this item. - /// - /// The to add. - public void Add(T item) - { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (items.Contains(item)) - { - throw new InvalidOperationException("Item is already part of this NativeListItem."); - } - - items.Add(item); - - if (items.Count == 1) - { - UpdateIndex(); - } - } - /// - /// Adds a in a specific location. - /// - /// The position where the item should be added. - /// The to add. - public void Add(int position, T item) - { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (position < 0 || position > Items.Count) - { - throw new ArgumentOutOfRangeException(nameof(position), "The position is out of the range of items."); - } - - Items.Insert(position, item); - - FixIndexIfRequired(); - } - /// - /// Removes a specific . - /// - /// The to remove. - public void Remove(T item) - { - if (items.Remove(item)) - { - FixIndexIfRequired(); - } - } - /// - /// Removes a at a specific location. - /// - /// The position of the . - public void RemoveAt(int position) - { - if (position >= items.Count) - { - return; - } - - items.RemoveAt(position); - FixIndexIfRequired(); - } - /// - /// Removes all of the items that match the . - /// - /// The function to use as a check. - public void Remove(Func pred) - { - if (items.RemoveAll(pred.Invoke) > 0) - { - FixIndexIfRequired(); - } - } - /// - /// Removes all of the from this item. - /// - public void Clear() - { - items.Clear(); - - UpdateIndex(); - } - /// - /// Recalculates the item positions and sizes with the specified values. - /// - /// The position of the item. - /// The size of the item. - /// If this item has been selected. - public override void Recalculate(PointF pos, SizeF size, bool selected) - { - base.Recalculate(pos, size, selected); - - text.Position = new PointF(pos.X + size.Width - RightArrow.Size.Width - 1 - text.Width, pos.Y + 3); - LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, pos.Y + 4); - } - /// - /// Moves to the previous item. - /// - public override void GoLeft() - { - if (Items.Count == 0) - { - return; - } - - if (index == 0) - { - index = Items.Count - 1; - } - else - { - index--; - } - - TriggerEvent(index, Direction.Left); - UpdateIndex(); - } - /// - /// Moves to the next item. - /// - public override void GoRight() - { - if (Items.Count == 0) - { - return; - } - - if (index == Items.Count - 1) - { - index = 0; - } - else - { - index++; - } - - TriggerEvent(index, Direction.Right); - UpdateIndex(); - } - /// - /// Draws the List on the screen. - /// - public override void Draw() - { - base.Draw(); // Arrows, Title and Left Badge - text.Draw(); - } - /// - public override void UpdateColors() + public NativeListItem(string title, string subtitle) : base(title, subtitle) { - base.UpdateColors(); - - if (!Enabled) - { - text.Color = Colors.TitleDisabled; - } - else if (lastSelected) - { - text.Color = Colors.TitleHovered; - } - else - { - text.Color = Colors.TitleNormal; - } + text = new ScaledText(PointF.Empty, string.Empty, 0.35f); } #endregion diff --git a/LemonUI/Menus/NativeListItem{T}.cs b/LemonUI/Menus/NativeListItem{T}.cs new file mode 100644 index 00000000..9ee0f659 --- /dev/null +++ b/LemonUI/Menus/NativeListItem{T}.cs @@ -0,0 +1,349 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; + +namespace LemonUI.Menus +{ + /// + /// An item that allows you to scroll between a set of objects. + /// + public class NativeListItem : NativeListItem, IEnumerable + { + #region Fields + + private int index = 0; + private List items = new List(); + + #endregion + + #region Properties + + /// + /// The index of the currently selected index. + /// + public int SelectedIndex + { + get + { + if (Items.Count == 0) + { + return -1; + } + return index; + } + set + { + if (Items.Count == 0) + { + throw new InvalidOperationException("There are no available items."); + } + if (value < 0) + { + throw new InvalidOperationException("The index is under zero."); + } + if (value >= Items.Count) + { + throw new InvalidOperationException($"The index is over the limit of {Items.Count - 1}"); + } + if (index == value) + { + return; + } + index = value; + TriggerEvent(value, Direction.Unknown); + UpdateIndex(); + } + } + /// + /// The currently selected item. + /// + public T SelectedItem + { + get + { + if (Items.Count == 0) + { + return default; + } + + return Items[SelectedIndex]; + } + set + { + if (Items.Count == 0) + { + throw new InvalidOperationException("There are no available items."); + } + + int newIndex = Items.IndexOf(value); + + if (newIndex == -1) + { + throw new InvalidOperationException("The object is not the list of Items."); + } + + SelectedIndex = newIndex; + } + } + /// + /// The objects used by this item. + /// + public List Items + { + get => items; + set + { + items = value; + UpdateIndex(); + } + } + + #endregion + + #region Events + + /// + /// Event triggered when the selected item is changed. + /// + public event ItemChangedEventHandler ItemChanged; + + #endregion + + #region Constructors + + /// + /// Creates a new . + /// + /// The title of the Item. + /// The objects that are available on the Item. + public NativeListItem(string title, params T[] objs) : this(title, string.Empty, objs) + { + } + /// + /// Creates a new . + /// + /// The title of the Item. + /// The subtitle of the Item. + /// The objects that are available on the Item. + public NativeListItem(string title, string subtitle, params T[] objs) : base(title, subtitle) + { + items = new List(); + items.AddRange(objs); + UpdateIndex(); + } + + #endregion + + #region Tools + + /// + /// Triggers the event. + /// + private void TriggerEvent(int index, Direction direction) + { + ItemChanged?.Invoke(this, new ItemChangedEventArgs(items[index], index, direction)); + } + private void FixIndexIfRequired() + { + if (index >= items.Count) + { + index = items.Count - 1; + UpdateIndex(); + } + } + /// + /// Updates the currently selected item based on the index. + /// + private void UpdateIndex() + { + text.Text = SelectedIndex != -1 ? SelectedItem.ToString() : string.Empty; + + text.Position = new PointF(RightArrow.Position.X - text.Width + 3, text.Position.Y); + LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, LeftArrow.Position.Y); + } + + #endregion + + #region Functions + + /// + public IEnumerator GetEnumerator() => Items.GetEnumerator(); + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + /// + /// Adds a into this item. + /// + /// The to add. + public void Add(T item) + { + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + if (items.Contains(item)) + { + throw new InvalidOperationException("Item is already part of this NativeListItem."); + } + + items.Add(item); + + if (items.Count == 1) + { + UpdateIndex(); + } + } + /// + /// Adds a in a specific location. + /// + /// The position where the item should be added. + /// The to add. + public void Add(int position, T item) + { + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + if (position < 0 || position > Items.Count) + { + throw new ArgumentOutOfRangeException(nameof(position), "The position is out of the range of items."); + } + + Items.Insert(position, item); + + FixIndexIfRequired(); + } + /// + /// Removes a specific . + /// + /// The to remove. + public void Remove(T item) + { + if (items.Remove(item)) + { + FixIndexIfRequired(); + } + } + /// + /// Removes a at a specific location. + /// + /// The position of the . + public void RemoveAt(int position) + { + if (position >= items.Count) + { + return; + } + + items.RemoveAt(position); + FixIndexIfRequired(); + } + /// + /// Removes all of the items that match the . + /// + /// The function to use as a check. + public void Remove(Func pred) + { + if (items.RemoveAll(pred.Invoke) > 0) + { + FixIndexIfRequired(); + } + } + /// + /// Removes all of the from this item. + /// + public void Clear() + { + items.Clear(); + + UpdateIndex(); + } + /// + /// Recalculates the item positions and sizes with the specified values. + /// + /// The position of the item. + /// The size of the item. + /// If this item has been selected. + public override void Recalculate(PointF pos, SizeF size, bool selected) + { + base.Recalculate(pos, size, selected); + + text.Position = new PointF(pos.X + size.Width - RightArrow.Size.Width - 1 - text.Width, pos.Y + 3); + LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, pos.Y + 4); + } + /// + /// Moves to the previous item. + /// + public override void GoLeft() + { + if (Items.Count == 0) + { + return; + } + + if (index == 0) + { + index = Items.Count - 1; + } + else + { + index--; + } + + TriggerEvent(index, Direction.Left); + UpdateIndex(); + } + /// + /// Moves to the next item. + /// + public override void GoRight() + { + if (Items.Count == 0) + { + return; + } + + if (index == Items.Count - 1) + { + index = 0; + } + else + { + index++; + } + + TriggerEvent(index, Direction.Right); + UpdateIndex(); + } + /// + /// Draws the List on the screen. + /// + public override void Draw() + { + base.Draw(); // Arrows, Title and Left Badge + text.Draw(); + } + /// + public override void UpdateColors() + { + base.UpdateColors(); + + if (!Enabled) + { + text.Color = Colors.TitleDisabled; + } + else if (lastSelected) + { + text.Color = Colors.TitleHovered; + } + else + { + text.Color = Colors.TitleNormal; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/LemonUI/Menus/NativeMenu.cs b/LemonUI/Menus/NativeMenu.cs index 317811e5..f1834fe1 100644 --- a/LemonUI/Menus/NativeMenu.cs +++ b/LemonUI/Menus/NativeMenu.cs @@ -3,6 +3,11 @@ using CitizenFX.Core.Native; using CitizenFX.Core.UI; using Font = CitizenFX.Core.UI.Font; +#elif ALTV +using AltV.Net.Client; +using Font = LemonUI.Elements.Font; +using CancelEventArgs = System.ComponentModel.CancelEventArgs; +using CancelEventHandler = System.ComponentModel.CancelEventHandler; #elif RAGEMP using RAGE.Game; using InstructionalButton = LemonUI.Scaleform.InstructionalButton; @@ -27,6 +32,7 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; +using System.Linq; namespace LemonUI.Menus { @@ -35,7 +41,40 @@ namespace LemonUI.Menus /// public class NativeMenu : IContainer, IEnumerable { - #region Public Fields + #region Constants + + /// + /// The height of the menu name background. + /// + internal const float nameHeight = 38; + /// + /// The height of one of the items in the screen. + /// + internal const float itemHeight = 37.4f; + /// + /// The height difference between the description and the end of the items. + /// + internal const float heightDiffDescImg = 4; + /// + /// The height difference between the background and text of the description. + /// + internal const float heightDiffDescTxt = 3; + /// + /// The X position of the description text. + /// + internal const float posXDescTxt = 6; + /// + /// The offset to the X value of the item title. + /// + internal const float itemOffsetX = 6; + /// + /// The offset to the Y value of the item title. + /// + internal const float itemOffsetY = 3; + + #endregion + + #region Fields /// /// The default played when the current is changed or activated. @@ -58,91 +97,23 @@ public class NativeMenu : IContainer, IEnumerable /// public static readonly Sound DefaultDisabledSound = new Sound("HUD_FRONTEND_DEFAULT_SOUNDSET", "ERROR"); - #endregion - - #region Internal Fields - internal static readonly Color colorWhiteSmoke = Color.FromArgb(255, 245, 245, 245); /// /// The search area size for the cursor rotation. /// internal static readonly SizeF searchAreaSize = new SizeF(30, 1080); /// - /// The controls required by the menu with both a gamepad and mouse + keyboard. - /// - internal static List controlsRequired = new List - { - // Menu Controls - Control.FrontendAccept, - Control.FrontendAxisX, - Control.FrontendAxisY, - Control.FrontendDown, - Control.FrontendUp, - Control.FrontendLeft, - Control.FrontendRight, - Control.FrontendCancel, - Control.FrontendSelect, - Control.CursorScrollDown, - Control.CursorScrollUp, - Control.CursorX, - Control.CursorY, - Control.MoveUpDown, - Control.MoveLeftRight, - // Camera - Control.LookBehind, - Control.VehicleLookBehind, - // Player - Control.Sprint, - Control.Jump, - Control.Enter, - Control.SpecialAbility, - Control.SpecialAbilityPC, - Control.SpecialAbilitySecondary, - Control.VehicleSpecialAbilityFranklin, - // Driving - Control.VehicleExit, - Control.VehicleAccelerate, - Control.VehicleBrake, - Control.VehicleMoveLeftRight, - Control.VehicleHandbrake, - Control.VehicleHorn, - // Bikes - Control.VehiclePushbikePedal, - Control.VehiclePushbikeSprint, - Control.VehiclePushbikeFrontBrake, - Control.VehiclePushbikeRearBrake, - // Flying - Control.VehicleFlyThrottleUp, - Control.VehicleFlyThrottleDown, - Control.VehicleFlyYawLeft, - Control.VehicleFlyYawRight, - Control.VehicleFlyRollLeftRight, - Control.VehicleFlyRollLeftOnly, - Control.VehicleFlyRollRightOnly, - Control.VehicleFlyPitchUpDown, - Control.VehicleFlyPitchUpOnly, - Control.VehicleFlyPitchDownOnly, -#if RPH - Control.ScriptedFlyUpDown, - Control.ScriptedFlyLeftRight, -#else - Control.FlyUpDown, - Control.FlyLeftRight, -#endif - // Rockstar Editor - Control.SaveReplayClip, - Control.ReplayStartStopRecording, - Control.ReplayStartStopRecordingSecondary, - Control.ReplayRecord, - Control.ReplaySave, - }; - /// /// Controls required for the camera to work. /// internal static readonly List controlsCamera = new List { +#if ALTV + Control.LookUd, + Control.LookLr, +#else Control.LookUpDown, Control.LookLeftRight, +#endif }; /// /// The controls required in a gamepad. @@ -153,47 +124,10 @@ public class NativeMenu : IContainer, IEnumerable Control.Attack }; - #endregion - - #region Constant fields - - /// - /// The height of the menu subtitle background. - /// - internal const float subtitleHeight = 38; - /// - /// The height of one of the items in the screen. - /// - internal const float itemHeight = 37.4f; - /// - /// The height difference between the description and the end of the items. - /// - internal const float heightDiffDescImg = 4; - /// - /// The height difference between the background and text of the description. - /// - internal const float heightDiffDescTxt = 3; - /// - /// The X position of the description text. - /// - internal const float posXDescTxt = 6; - /// - /// The offset to the X value of the item title. - /// - internal const float itemOffsetX = 6; - /// - /// The offset to the Y value of the item title. - /// - internal const float itemOffsetY = 3; - - #endregion - - #region Private Fields - /// - /// A list of GTA V Controls. + /// A list of GTA V Controls that are not required by the menu with both a gamepad and mouse + keyboard. /// - private static readonly Control[] controls = (Control[])Enum.GetValues(typeof(Control)); + private static readonly Control[] controls; /// /// If the menu has just been opened and we should check the controls. /// @@ -203,14 +137,18 @@ public class NativeMenu : IContainer, IEnumerable /// private List visibleItems = new List(); /// - /// The subtitle of the menu, without any changes. + /// The name of the menu, without any changes. /// - private string subtitle = string.Empty; + private string name = string.Empty; /// /// If the menu is visible or not. /// private bool visible = false; /// + /// If the menu has just been closed. + /// + private bool justClosed = false; + /// /// If this menu should be aware of the Safe Zone when doing calculations. /// private bool safeZoneAware = true; @@ -237,14 +175,14 @@ public class NativeMenu : IContainer, IEnumerable /// /// The background of the drawable text. /// - private readonly ScaledRectangle subtitleImage = new ScaledRectangle(PointF.Empty, SizeF.Empty) + private readonly ScaledRectangle nameImage = new ScaledRectangle(PointF.Empty, SizeF.Empty) { Color = Color.FromArgb(255, 0, 0, 0) }; /// - /// The text of the subtitle. + /// The text of the name. /// - private readonly ScaledText subtitleText = new ScaledText(PointF.Empty, string.Empty, 0.345f, Font.ChaletLondon) + private readonly ScaledText nameText = new ScaledText(PointF.Empty, string.Empty, 0.345f, Font.ChaletLondon) { Color = colorWhiteSmoke }; @@ -288,20 +226,16 @@ public class NativeMenu : IContainer, IEnumerable /// private PointF searchAreaRight = PointF.Empty; /// - /// The time sice the player has been pressing the Up button. + /// The time since the player has been pressing the Up button. /// - private long upSince = -1; - /// - /// The time sice the player has been pressing the Down button. - /// - private long downSince = -1; - private SubtitleBehavior subtitleBehavior = SubtitleBehavior.AlwaysShow; + private long heldSince = -1; + private HeaderBehavior nameBehavior = HeaderBehavior.AlwaysShow; #endregion #region Properties - private bool ShouldDrawSubtitleBackground => subtitleBehavior == SubtitleBehavior.AlwaysShow || (subtitleBehavior == SubtitleBehavior.ShowIfRequired && (ShouldDrawCount || !string.IsNullOrWhiteSpace(subtitle))); + private bool ShouldDrawNameBackground => nameBehavior == HeaderBehavior.AlwaysShow || (nameBehavior == HeaderBehavior.ShowIfRequired && (ShouldDrawCount || !string.IsNullOrWhiteSpace(name))); private bool ShouldDrawCount => ItemCount == CountVisibility.Always || (ItemCount == CountVisibility.Auto && Items.Count > MaxItems); /// @@ -349,30 +283,42 @@ public bool Visible } visible = false; + justClosed = true; Closed?.Invoke(this, EventArgs.Empty); SoundClose?.PlayFrontend(); } } } + /// - /// The title of the menu. + /// The text shown on top of the banner. /// - public ScaledText Title { get; set; } + public ScaledText BannerText { get; set; } /// - /// The font of title menu text. + /// The text shown on top of the banner. /// + [Obsolete("Please use BannerText instead.", true)] + public ScaledText Title + { + get => BannerText; + set => BannerText = value; + } + /// + /// The font of the text shown on top of the banner. + /// + [Obsolete("Please use BannerText.Font instead.", true)] public Font TitleFont { - get => Title.Font; - set => Title.Font = value; + get => BannerText.Font; + set => BannerText.Font = value; } /// - /// The font of subtitle text. + /// The font of name text. /// - public Font SubtitleFont + public Font NameFont { - get => subtitleText.Font; - set => subtitleText.Font = value; + get => nameText.Font; + set => nameText.Font = value; } /// /// The font of description text. @@ -564,18 +510,30 @@ public Alignment Alignment } } /// - /// The subtitle of the menu. + /// The name of this menu. /// - public string Subtitle + /// + /// This is shown under the menu banner, and by the menu items when added as a submenu. + /// + public string Name { - get => subtitle; + get => name; set { - subtitle = value; - subtitleText.Text = value.ToUpperInvariant(); + name = value; + nameText.Text = value.ToUpperInvariant(); } } /// + /// The name of the menu. + /// + [Obsolete("Please use Name instead.", true)] + public string Subtitle + { + get => Name; + set => Name = value; + } + /// /// The description used when this menu is used as a submenu. /// public string Description { get; set; } = string.Empty; @@ -633,7 +591,7 @@ public bool SafeZoneAware } } /// - /// If the count of items should be shown on the right of the subtitle. + /// If the count of items should be shown on the right of the name. /// public CountVisibility ItemCount { get; set; } /// @@ -670,19 +628,28 @@ public bool SafeZoneAware /// public List RequiredControls { get; } = new List(); /// - /// The behavior of the black bar showing the subtitle. + /// The behavior of the black bar showing the name. /// + [Obsolete("Please use NameBehavior instead.", true)] public SubtitleBehavior SubtitleBehavior { - get => subtitleBehavior; + get => (SubtitleBehavior)HeaderBehavior; + set => HeaderBehavior = (HeaderBehavior)value; + } + /// + /// The behavior of the black bar showing the name. + /// + public HeaderBehavior HeaderBehavior + { + get => nameBehavior; set { - if (subtitleBehavior == value) + if (nameBehavior == value) { return; } - subtitleBehavior = value; + nameBehavior = value; Recalculate(); } } @@ -746,7 +713,119 @@ public SubtitleBehavior SubtitleBehavior #endregion - #region Constructor + #region Constructors + + static NativeMenu() + { + // The controls required by the menu with both a gamepad and mouse + keyboard + HashSet controlsRequired = new HashSet + { + // Menu Controls + Control.FrontendAccept, + Control.FrontendAxisX, + Control.FrontendAxisY, + Control.FrontendDown, + Control.FrontendUp, + Control.FrontendLeft, + Control.FrontendRight, + Control.FrontendCancel, + Control.FrontendSelect, + Control.CursorScrollDown, + Control.CursorScrollUp, + Control.CursorX, + Control.CursorY, +#if ALTV + Control.MoveUd, + Control.MoveLr, +#else + Control.MoveUpDown, + Control.MoveLeftRight, +#endif + // Camera + Control.LookBehind, +#if ALTV + Control.VehLookBehind, +#else + Control.VehicleLookBehind, +#endif + // Player + Control.Sprint, + Control.Jump, + Control.Enter, + Control.SpecialAbility, + Control.SpecialAbilityPC, + Control.SpecialAbilitySecondary, +#if ALTV + Control.VehSpecialAbilityFranklin, + // Driving + Control.VehExit, + Control.VehAccelerate, + Control.VehBrake, + Control.VehMoveLr, + Control.VehHandbrake, + Control.VehHorn, + // Bikes + Control.VehPushbikePedal, + Control.VehPushbikeSprint, + Control.VehPushbikeFrontBrake, + Control.VehPushbikeRearBrake, + // Flying + Control.VehFlyThrottleUp, + Control.VehFlyThrottleDown, + Control.VehFlyYawLeft, + Control.VehFlyYawRight, + Control.VehFlyRollLR, + Control.VehFlyRollLeftOnly, + Control.VehFlyRollRightOnly, + Control.VehFlyPitchUD, + Control.VehFlyPitchUpOnly, + Control.VehFlyPitchDownOnly, +#else + Control.VehicleSpecialAbilityFranklin, + // Driving + Control.VehicleExit, + Control.VehicleAccelerate, + Control.VehicleBrake, + Control.VehicleMoveLeftRight, + Control.VehicleHandbrake, + Control.VehicleHorn, + // Bikes + Control.VehiclePushbikePedal, + Control.VehiclePushbikeSprint, + Control.VehiclePushbikeFrontBrake, + Control.VehiclePushbikeRearBrake, + // Flying + Control.VehicleFlyThrottleUp, + Control.VehicleFlyThrottleDown, + Control.VehicleFlyYawLeft, + Control.VehicleFlyYawRight, + Control.VehicleFlyRollLeftRight, + Control.VehicleFlyRollLeftOnly, + Control.VehicleFlyRollRightOnly, + Control.VehicleFlyPitchUpDown, + Control.VehicleFlyPitchUpOnly, + Control.VehicleFlyPitchDownOnly, +#endif +#if RPH + Control.ScriptedFlyUpDown, + Control.ScriptedFlyLeftRight, +#elif ALTV + Control.ScriptedFlyUd, + Control.ScriptedFlyLr, +#else + Control.FlyUpDown, + Control.FlyLeftRight, +#endif + // Rockstar Editor + Control.SaveReplayClip, + Control.ReplayStartStopRecording, + Control.ReplayStartStopRecordingSecondary, + Control.ReplayRecord, + Control.ReplaySave, + }; + + controls = ((Control[])Enum.GetValues(typeof(Control))).Except(controlsRequired).ToArray(); + } /// /// Creates a new menu with the specified title. @@ -757,47 +836,47 @@ public NativeMenu(string title) : this(title, string.Empty, string.Empty) } /// - /// Creates a new menu with the specified title and subtitle. + /// Creates a new menu with the specified banner text and name. /// - /// The title of the menu. - /// The subtitle of this menu. - public NativeMenu(string title, string subtitle) : this(title, subtitle, string.Empty) + /// The title of the menu. + /// The name of this menu. + public NativeMenu(string bqnnerText, string name) : this(bqnnerText, name, string.Empty) { } /// - /// Creates a new menu with the specified title, subtitle and description. + /// Creates a new menu with the specified banner text, name and description. /// - /// The title of the menu. - /// The subtitle of this menu. + /// The title of the menu. + /// The name of this menu. /// The description used for submenus. - public NativeMenu(string title, string subtitle, string description) : this(title, subtitle, description, new ScaledTexture(PointF.Empty, new SizeF(0, 108), "commonmenu", "interaction_bgd")) + public NativeMenu(string bqnnerText, string name, string description) : this(bqnnerText, name, description, new ScaledTexture(PointF.Empty, new SizeF(0, 108), "commonmenu", "interaction_bgd")) { } /// - /// Creates a new menu with the specified title, subtitle, description and banner. + /// Creates a new menu with the specified banner text, name, description and banner. /// - /// The title of the menu. - /// The subtitle of this menu. + /// The title of the menu. + /// The name of this menu. /// The description used for submenus. /// The drawable to use as the banner. - public NativeMenu(string title, string subtitle, string description, I2Dimensional banner) + public NativeMenu(string bqnnerText, string name, string description, I2Dimensional banner) { - this.subtitle = subtitle; + this.name = name; Description = description; bannerImage = banner; - Title = new ScaledText(PointF.Empty, title, 1.02f, Font.HouseScript) + BannerText = new ScaledText(PointF.Empty, bqnnerText, 1.02f, Font.HouseScript) { Alignment = Alignment.Center }; - subtitleText.Text = subtitle.ToUpperInvariant(); + nameText.Text = name.ToUpperInvariant(); Recalculate(); } #endregion - #region Private Functions + #region Tools /// /// Updates the list of visible items on the screen. @@ -866,7 +945,7 @@ private void RecalculatePanel() /// /// Resets the current position of the cursor. /// - private void ResetCursor() + public void ResetCursor() { const float extraX = 35; const float extraY = 325; @@ -910,8 +989,10 @@ private void ResetCursor() Invoker.Invoke(Natives.SetCursorLocation, pos.X, pos.Y); #elif RPH NativeFunction.CallByHash(0xFC695459D4D0E219, pos.X, pos.Y); +#elif ALTV + Alt.Natives.SetCursorPosition(pos.X, pos.Y); #elif SHVDN3 - Function.Call(Hash._SET_CURSOR_LOCATION, pos.X, pos.Y); + Function.Call(Hash.SET_CURSOR_POSITION, pos.X, pos.Y); #endif } /// @@ -952,16 +1033,16 @@ private void UpdateItems() pos = new PointF(x, Offset.Y); } - // Add the heights of the banner and subtitle (if there are any) + // Add the heights of the banner and title (if there are any) if (bannerImage != null) { pos.Y += bannerImage.Size.Height; } - if (ShouldDrawSubtitleBackground || ShouldDrawCount) + if (ShouldDrawNameBackground || ShouldDrawCount) { countText.Text = $"{SelectedIndex + 1} / {Items.Count}"; countText.Position = new PointF(pos.X + width - countText.Width - 6, pos.Y + 4.2f); - pos.Y += subtitleImage.Size.Height; + pos.Y += nameImage.Size.Height; } // Set the position and size of the background image @@ -1009,20 +1090,17 @@ private void ProcessControls() // If the user wants to disable the controls, do so but only the ones required if (DisableControls) { + bool isUsingController = Controls.IsUsingController; + foreach (Control control in controls) { - // If the control is required by the menu - if (controlsRequired.Contains(control)) - { - continue; - } // If the player is using a controller and is required on gamepads - if (Controls.IsUsingController && controlsGamepad.Contains(control)) + if (isUsingController && controlsGamepad.Contains(control)) { continue; } // If the player is usinng a controller or mouse usage is disabled and is a camera control - if ((Controls.IsUsingController || !UseMouse) && controlsCamera.Contains(control)) + if ((isUsingController || !UseMouse) && controlsCamera.Contains(control)) { continue; } @@ -1051,6 +1129,8 @@ private void ProcessControls() // If the controls are disabled, the menu has just been opened or the text input field is active, return #if FIVEM bool isKeyboardActive = API.UpdateOnscreenKeyboard() == 0; +#elif ALTV + bool isKeyboardActive = Alt.Natives.UpdateOnscreenKeyboard() == 0; #elif RAGEMP bool isKeyboardActive = Invoker.Invoke(Natives.UpdateOnscreenKeyboard) == 0; #elif RPH @@ -1072,6 +1152,8 @@ private void ProcessControls() bool leftPressed = Controls.IsJustPressed((Control)174 /*PhoneLeft*/); bool rightPressed = Controls.IsJustPressed((Control)175 /*PhoneRight*/); + bool leftHeld = Controls.IsPressed((Control)174 /*PhoneLeft*/); + bool rightHeld = Controls.IsPressed((Control)175 /*PhoneRight*/); bool upHeld = Controls.IsPressed((Control)172 /*PhoneUp*/) || Controls.IsPressed(Control.CursorScrollUp); bool downHeld = Controls.IsPressed((Control)173 /*PhoneDown*/) || Controls.IsPressed(Control.CursorScrollDown); @@ -1084,23 +1166,37 @@ private void ProcessControls() #if RAGEMP int time = Misc.GetGameTimer(); +#elif ALTV + int time = Alt.MsPerGameMinute; #elif RPH uint time = Game.GameTime; #else int time = Game.GameTime; #endif + if (HeldTime > 0 && (upHeld || downHeld || leftHeld || rightHeld)) + { + if (heldSince == -1) + { + heldSince = time; + } + } + else + { + heldSince = -1; + } + // If the player pressed up, go to the previous item - if ((upPressed && !downPressed) || (HeldTime > 0 && upSince != -1 && !upPressed && upHeld && upSince + HeldTime < time)) + if ((upPressed && !downPressed) || (upHeld && !downHeld && heldSince > 0 && heldSince + HeldTime < time)) { - upSince = time; + heldSince = time; Previous(); return; } // If he pressed down, go to the next item - if ((downPressed && !upPressed) || (HeldTime > 0 && downSince != -1 && !downPressed && downHeld && downSince + HeldTime < time)) + if ((downPressed && !upPressed) || (downHeld && !upHeld && heldSince > 0 && heldSince + HeldTime < time)) { - downSince = time; + heldSince = time; Next(); return; } @@ -1112,7 +1208,7 @@ private void ProcessControls() if (UseMouse && !Controls.IsUsingController) { // Enable the mouse cursor -#if FIVEM || SHVDN3 +#if FIVEM || SHVDN3 || ALTV Screen.ShowCursorThisFrame(); #elif RAGEMP Invoker.Invoke(Natives.ShowCursorThisFrame); @@ -1127,6 +1223,9 @@ private void ProcessControls() { #if FIVEM || SHVDN3 GameplayCamera.RelativeHeading += 5; +#elif ALTV + float current = Alt.Natives.GetGameplayCamRelativeHeading(); + Alt.Natives.SetGameplayCamRelativeHeading(current + 5); #elif RAGEMP float current = Invoker.Invoke(0x743607648ADD4587); Invoker.Invoke(0xB4EC2312F4E5B1F1, current + 5); @@ -1138,6 +1237,9 @@ private void ProcessControls() { #if FIVEM || SHVDN3 GameplayCamera.RelativeHeading -= 5; +#elif ALTV + float current = Alt.Natives.GetGameplayCamRelativeHeading(); + Alt.Natives.SetGameplayCamRelativeHeading(current - 5); #elif RAGEMP float current = Invoker.Invoke(0x743607648ADD4587); Invoker.Invoke(0xB4EC2312F4E5B1F1, current - 5); @@ -1233,10 +1335,12 @@ private void ProcessControls() } // If the player pressed the left or right button, trigger the event and sound - if (SelectedItem is NativeSlidableItem slidableItem) + if (SelectedItem is NativeSlidableItem slidableItem && !upHeld && !downHeld) { - if (leftPressed) + if ((leftPressed && !rightPressed) || (leftHeld && heldSince > 0 && heldSince + HeldTime < time)) { + heldSince = time; + if (SelectedItem.Enabled) { slidableItem.GoLeft(); @@ -1248,8 +1352,10 @@ private void ProcessControls() } return; } - if (rightPressed) + if ((rightPressed && !leftPressed) || (rightHeld && heldSince > 0 && heldSince + HeldTime < time)) { + heldSince = time; + if (SelectedItem.Enabled) { slidableItem.GoRight(); @@ -1292,13 +1398,13 @@ private void Draw() if (bannerImage != null) { bannerImage.Draw(); - Title?.Draw(); + BannerText?.Draw(); } - if (ShouldDrawSubtitleBackground) + if (ShouldDrawNameBackground) { - subtitleImage.Draw(); - subtitleText?.Draw(); + nameImage.Draw(); + nameText?.Draw(); if (ShouldDrawCount) { countText.Draw(); @@ -1354,7 +1460,7 @@ private void Draw() #endregion - #region Public Functions + #region Functions /// public IEnumerator GetEnumerator() => Items.GetEnumerator(); @@ -1523,6 +1629,33 @@ public virtual void Process() { if (!visible) { + if (!justClosed) + { + return; + } + +#if FIVEM + API.SetInputExclusive(0, (int)Control.PhoneCancel); + API.SetInputExclusive(0, (int)Control.FrontendPause); +#elif ALTV + Alt.Natives.SetInputExclusive(0, (int)Control.CellPhoneCancel); + Alt.Natives.SetInputExclusive(0, (int)Control.FrontendPause); +#elif RAGEMP + Invoker.Invoke(Natives.SetInputExclusive, 0, (int)Control.PhoneCancel); + Invoker.Invoke(Natives.SetInputExclusive, 0, (int)Control.FrontendPause); +#elif RPH + NativeFunction.CallByHash(0x351220255D64C155, 0, (int)Control.CellphoneCancel); + NativeFunction.CallByHash(0x351220255D64C155, 0, (int)Control.FrontendPause); +#elif SHVDN3 + Function.Call(Hash.SET_INPUT_EXCLUSIVE, 0, (int)Control.PhoneCancel); + Function.Call(Hash.SET_INPUT_EXCLUSIVE, 0, (int)Control.FrontendPause); +#endif + + if (!Controls.IsPressed((Control)177 /*PhoneCancel*/) && !Controls.IsPressed(Control.FrontendPause)) + { + justClosed = false; + } + return; } @@ -1582,26 +1715,26 @@ public virtual void Recalculate() bannerImageBase.literalSize = new SizeF(width, bannerImageBase.Size.Height); bannerImageBase.Recalculate(); // If there is a text element, also set the position of it - if (Title != null) + if (BannerText != null) { - Title.Position = new PointF(pos.X + 209, pos.Y + 22); + BannerText.Position = new PointF(pos.X + 209, pos.Y + 22); } // Finally, increase the current position of Y based on the banner height pos.Y += bannerImageBase.Size.Height; } - // Time for the subtitle background + // Time for the name background // Set the position and size of it - subtitleImage.literalPosition = new PointF(pos.X, pos.Y); - subtitleImage.literalSize = new SizeF(width, subtitleHeight); - subtitleImage.Recalculate(); + nameImage.literalPosition = new PointF(pos.X, pos.Y); + nameImage.literalSize = new SizeF(width, nameHeight); + nameImage.Recalculate(); // If there is a text, also set the position of it - if (subtitleText != null) + if (nameText != null) { - subtitleText.Position = new PointF(pos.X + 6, pos.Y + 4.2f); + nameText.Position = new PointF(pos.X + 6, pos.Y + 4.2f); } - // Finally, increase the size based on the subtitle height - // currentY += subtitleHeight; + // Finally, increase the size based on the name height + // currentY += nameHeight; // Set the size of the selection rectangle selectedRect.Size = new SizeF(width, itemHeight); @@ -1619,10 +1752,16 @@ public virtual void Recalculate() /// public void Back() { - // Try to close the menu Visible = false; - // If this menu has been closed and there is a parent menu, open it - if (!Visible && Parent != null) + + if (Visible) + { + return; + } + + justClosed = true; + + if (Parent != null) { Parent.Visible = true; } diff --git a/LemonUI/Menus/NativePanel.cs b/LemonUI/Menus/NativePanel.cs index 6214348c..32cbe26b 100644 --- a/LemonUI/Menus/NativePanel.cs +++ b/LemonUI/Menus/NativePanel.cs @@ -8,7 +8,7 @@ namespace LemonUI.Menus /// public abstract class NativePanel { - #region Public Properties + #region Properties /// /// If this panel is visible to the user. @@ -25,7 +25,7 @@ public abstract class NativePanel #endregion - #region Public Functions + #region Functions /// /// Recalculates the menu contents. diff --git a/LemonUI/Menus/NativeSeparatorItem.cs b/LemonUI/Menus/NativeSeparatorItem.cs index 46d7d568..2633e542 100644 --- a/LemonUI/Menus/NativeSeparatorItem.cs +++ b/LemonUI/Menus/NativeSeparatorItem.cs @@ -5,7 +5,7 @@ /// public class NativeSeparatorItem : NativeItem { - #region Constructor + #region Constructors /// /// Creates a new Menu Separator. @@ -16,7 +16,7 @@ public NativeSeparatorItem() : base(string.Empty, string.Empty, string.Empty) #endregion - #region Public Functions + #region Functions /// /// Draws nothing. diff --git a/LemonUI/Menus/NativeSlidableItem.cs b/LemonUI/Menus/NativeSlidableItem.cs index 3f459413..2e836519 100644 --- a/LemonUI/Menus/NativeSlidableItem.cs +++ b/LemonUI/Menus/NativeSlidableItem.cs @@ -9,13 +9,7 @@ namespace LemonUI.Menus /// public abstract class NativeSlidableItem : NativeItem { - #region Private Fields - - private bool alwaysVisible = false; - - #endregion - - #region Internal Fields + #region Fields /// /// The arrow pointing to the Left. @@ -28,9 +22,11 @@ public abstract class NativeSlidableItem : NativeItem [Obsolete("arrowRight is Obsolete, use RightArrow instead.")] internal protected ScaledTexture arrowRight = null; + private bool alwaysVisible = false; + #endregion - #region Public Properties + #region Properties /// /// The arrow pointing to the Left. @@ -75,13 +71,13 @@ public NativeSlidableItem(string title, string description) : base(title, descri #endregion - #region Local Events + #region Tools private void NativeSlidableItem_EnabledChanged(object sender, EventArgs e) => Recalculate(); #endregion - #region Public Functions + #region Functions /// /// Recalculates the item positions and sizes with the specified values. diff --git a/LemonUI/Menus/NativeSliderItem.cs b/LemonUI/Menus/NativeSliderItem.cs index 4472734a..bb86a798 100644 --- a/LemonUI/Menus/NativeSliderItem.cs +++ b/LemonUI/Menus/NativeSliderItem.cs @@ -9,7 +9,7 @@ namespace LemonUI.Menus /// public class NativeSliderItem : NativeSlidableItem { - #region Internal Fields + #region Fields /// /// The background of the slider. @@ -26,10 +26,6 @@ public class NativeSliderItem : NativeSlidableItem Color = Color.FromArgb(255, 57, 116, 200) }; - #endregion - - #region Private Fields - /// /// The maximum value of the slider. /// @@ -41,7 +37,7 @@ public class NativeSliderItem : NativeSlidableItem #endregion - #region Public Properties + #region Properties /// /// The color of the Slider. @@ -104,7 +100,7 @@ public int Value #endregion - #region Event + #region Events /// /// Event triggered when the value of the menu changes. @@ -154,7 +150,7 @@ public NativeSliderItem(string title, string description, int max, int value) : #endregion - #region Internal Functions + #region Tools /// /// Updates the position of the bar based on the value. @@ -170,7 +166,7 @@ internal protected void UpdatePosition() #endregion - #region Public Functions + #region Functions /// /// Recalculates the item positions and sizes with the specified values. diff --git a/LemonUI/Menus/NativeStatsInfo.cs b/LemonUI/Menus/NativeStatsInfo.cs index f26705ca..a187bb89 100644 --- a/LemonUI/Menus/NativeStatsInfo.cs +++ b/LemonUI/Menus/NativeStatsInfo.cs @@ -51,7 +51,7 @@ public float Value #endregion - #region Constructor + #region Constructors /// /// Creates a new Stat Info with the specified name and value set to zero. diff --git a/LemonUI/Menus/NativeStatsPanel.cs b/LemonUI/Menus/NativeStatsPanel.cs index 7e82019a..a320bcd5 100644 --- a/LemonUI/Menus/NativeStatsPanel.cs +++ b/LemonUI/Menus/NativeStatsPanel.cs @@ -57,7 +57,7 @@ public Color ForegroundColor #endregion - #region Constructor + #region Constructors /// /// Creates a new Stats Panel. diff --git a/LemonUI/Menus/NativeSubmenuItem.cs b/LemonUI/Menus/NativeSubmenuItem.cs index 973c591b..62ab6a6d 100644 --- a/LemonUI/Menus/NativeSubmenuItem.cs +++ b/LemonUI/Menus/NativeSubmenuItem.cs @@ -7,7 +7,7 @@ namespace LemonUI.Menus /// public class NativeSubmenuItem : NativeItem { - #region Public Properties + #region Properties /// /// The menu opened by this item. @@ -32,7 +32,7 @@ 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.Subtitle, menu.Description, endlabel) + 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)); @@ -42,32 +42,32 @@ public NativeSubmenuItem(NativeMenu menu, NativeMenu parent, string endlabel) : #endregion - #region Functions + #region Event Functions - /// - public override void Draw() + private void NativeSubmenuItem_Activated(object sender, EventArgs e) { - // There is no Process(), so let's use draw to update the description - if (Description != Menu.Description) + Menu.Parent.Visible = false; + + if (!Menu.Parent.Visible) { - Description = Menu.Description; + Menu.Visible = true; } - - base.Draw(); } #endregion - #region Local Events + #region Functions - private void NativeSubmenuItem_Activated(object sender, EventArgs e) + /// + public override void Draw() { - Menu.Parent.Visible = false; - - if (!Menu.Parent.Visible) + // There is no Process(), so let's use draw to update the description + if (Description != Menu.Description) { - Menu.Visible = true; + Description = Menu.Description; } + + base.Draw(); } #endregion diff --git a/LemonUI/Menus/SelectedEventArgs.cs b/LemonUI/Menus/SelectedEventArgs.cs index c44ab79f..c7a413aa 100644 --- a/LemonUI/Menus/SelectedEventArgs.cs +++ b/LemonUI/Menus/SelectedEventArgs.cs @@ -5,6 +5,8 @@ /// public class SelectedEventArgs { + #region Properties + /// /// The index of the item in the full list of items. /// @@ -14,6 +16,10 @@ public class SelectedEventArgs /// public int OnScreen { get; } + #endregion + + #region Constructors + /// /// Creates a new . /// @@ -24,5 +30,7 @@ public SelectedEventArgs(int index, int screen) Index = index; OnScreen = screen; } + + #endregion } } diff --git a/LemonUI/Menus/SubtitleBehavior.cs b/LemonUI/Menus/SubtitleBehavior.cs index 1d22f75a..2d6679ee 100644 --- a/LemonUI/Menus/SubtitleBehavior.cs +++ b/LemonUI/Menus/SubtitleBehavior.cs @@ -1,8 +1,11 @@ -namespace LemonUI.Menus +using System; + +namespace LemonUI.Menus { /// /// The behavior of the 's subtitle. /// + [Obsolete("Please use HeaderBehavior instead", true)] public enum SubtitleBehavior { /// diff --git a/LemonUI/ObjectPool.cs b/LemonUI/ObjectPool.cs index 68647a3b..07fb4b68 100644 --- a/LemonUI/ObjectPool.cs +++ b/LemonUI/ObjectPool.cs @@ -1,6 +1,4 @@ #if FIVEM -using CitizenFX.Core; -using CitizenFX.Core.UI; using CitizenFX.Core.Native; #elif RAGEMP using RAGE.Game; @@ -10,7 +8,8 @@ using Rage.Native; #elif SHVDN3 using GTA.Native; -using GTA.UI; +#elif ALTV +using AltV.Net.Client; #endif using System; using System.Collections; @@ -19,52 +18,20 @@ namespace LemonUI { - /// - /// Represents the method that reports a Resolution change in the Game Settings. - /// - /// The source of the event. - /// A containing the Previous and Current resolution. - public delegate void ResolutionChangedEventHandler(object sender, ResolutionChangedEventArgs e); - /// - /// Represents the method that reports a Safe Zone change in the Game Settings. - /// - /// The source of the event event. - /// A containing the Previous and Current Safe Zone. - public delegate void SafeZoneChangedEventHandler(object sender, SafeZoneChangedEventArgs e); - - /// - /// Represents the information after a Safe Zone Change in the game. - /// - public class SafeZoneChangedEventArgs - { - /// - /// The raw Safezone size before the change. - /// - public float Before { get; } - /// - /// The Safezone size after the change. - /// - public float After { get; } - - internal SafeZoneChangedEventArgs(float before, float after) - { - Before = before; - After = after; - } - } - /// /// Manager for Menus and Items. /// public class ObjectPool : IEnumerable { - #region Private Fields + #region Fields /// /// 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 @@ -77,6 +44,8 @@ public class ObjectPool : IEnumerable /// #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 @@ -84,6 +53,7 @@ public class ObjectPool : IEnumerable #elif SHVDN3 private float lastKnownSafezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE); #endif + /// /// The list of processable objects. /// @@ -91,7 +61,7 @@ public class ObjectPool : IEnumerable #endregion - #region Public Properties + #region Properties /// /// Checks if there are objects visible on the screen. @@ -136,6 +106,8 @@ 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); @@ -163,6 +135,8 @@ 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 @@ -185,7 +159,7 @@ private void DetectSafezoneChanges() #endregion - #region Public Function + #region Functions /// public IEnumerator GetEnumerator() => objects.GetEnumerator(); diff --git a/LemonUI/ResolutionChangedEventHandler.cs b/LemonUI/ResolutionChangedEventHandler.cs new file mode 100644 index 00000000..6bbf2e19 --- /dev/null +++ b/LemonUI/ResolutionChangedEventHandler.cs @@ -0,0 +1,9 @@ +namespace LemonUI +{ + /// + /// Represents the method that reports a Resolution change in the Game Settings. + /// + /// The source of the event. + /// A containing the Previous and Current resolution. + public delegate void ResolutionChangedEventHandler(object sender, ResolutionChangedEventArgs e); +} diff --git a/LemonUI/SafeZoneChangedEventArgs.cs b/LemonUI/SafeZoneChangedEventArgs.cs new file mode 100644 index 00000000..0f61b145 --- /dev/null +++ b/LemonUI/SafeZoneChangedEventArgs.cs @@ -0,0 +1,31 @@ +namespace LemonUI +{ + /// + /// Represents the information after a Safe Zone Change in the game. + /// + public class SafeZoneChangedEventArgs + { + #region Properties + + /// + /// The raw Safezone size before the change. + /// + public float Before { get; } + /// + /// The Safezone size after the change. + /// + public float After { get; } + + #endregion + + #region Constructors + + internal SafeZoneChangedEventArgs(float before, float after) + { + Before = before; + After = after; + } + + #endregion + } +} diff --git a/LemonUI/SafeZoneChangedEventHandler.cs b/LemonUI/SafeZoneChangedEventHandler.cs new file mode 100644 index 00000000..56943648 --- /dev/null +++ b/LemonUI/SafeZoneChangedEventHandler.cs @@ -0,0 +1,9 @@ +namespace LemonUI +{ + /// + /// Represents the method that reports a Safe Zone change in the Game Settings. + /// + /// The source of the event event. + /// A containing the Previous and Current Safe Zone. + public delegate void SafeZoneChangedEventHandler(object sender, SafeZoneChangedEventArgs e); +} diff --git a/LemonUI/Scaleform/BaseScaleform.cs b/LemonUI/Scaleform/BaseScaleform.cs index 9de7afb3..a404568e 100644 --- a/LemonUI/Scaleform/BaseScaleform.cs +++ b/LemonUI/Scaleform/BaseScaleform.cs @@ -4,6 +4,8 @@ using System.Threading.Tasks; #elif RAGEMP using RAGE.Game; +#elif ALTV +using AltV.Net.Client; #elif RPH using Rage.Native; #elif SHVDN3 @@ -19,7 +21,7 @@ namespace LemonUI.Scaleform /// public abstract class BaseScaleform : IScaleform { - #region Private Fields + #region Fields #if FIVEM || SHVDN3 /// @@ -35,7 +37,7 @@ public abstract class BaseScaleform : IScaleform #endregion - #region Public Properties + #region Properties /// /// The ID or Handle of the Scaleform. @@ -58,6 +60,8 @@ public bool IsLoaded { #if FIVEM return API.HasScaleformMovieLoaded(Handle); +#elif ALTV + return Alt.Natives.HasScaleformMovieLoaded(Handle); #elif RAGEMP return Invoker.Invoke(Natives.HasScaleformMovieLoaded, Handle); #elif RPH @@ -82,6 +86,8 @@ public BaseScaleform(string sc) #if FIVEM Handle = API.RequestScaleformMovie(Name); +#elif ALTV + Handle = Alt.Natives.RequestScaleformMovie(Name); #elif RAGEMP Handle = Invoker.Invoke(Natives.RequestScaleformMovie, Name); #elif RPH @@ -93,12 +99,14 @@ public BaseScaleform(string sc) #endregion - #region Private Functions + #region Tools private void CallFunctionBase(string function, params object[] parameters) { #if FIVEM API.BeginScaleformMovieMethod(Handle, function); +#elif ALTV + Alt.Natives.BeginScaleformMovieMethod(Handle, function); #elif RAGEMP Invoker.Invoke(0xF6E48914C7A8694E, Handle, function); #elif RPH @@ -113,6 +121,8 @@ private void CallFunctionBase(string function, params object[] parameters) { #if FIVEM API.ScaleformMovieMethodAddParamInt(objInt); +#elif ALTV + Alt.Natives.ScaleformMovieMethodAddParamInt(objInt); #elif RAGEMP Invoker.Invoke(0xC3D0841A0CC546A6, objInt); #elif RPH @@ -127,6 +137,10 @@ private void CallFunctionBase(string function, params object[] parameters) API.BeginTextCommandScaleformString("STRING"); API.AddTextComponentSubstringPlayerName(objString); API.EndTextCommandScaleformString(); +#elif ALTV + Alt.Natives.BeginTextCommandScaleformString("STRING"); + Alt.Natives.AddTextComponentSubstringPlayerName(objString); + Alt.Natives.EndTextCommandScaleformString(); #elif RAGEMP Invoker.Invoke(Natives.BeginTextCommandScaleformString, "STRING"); Invoker.Invoke(Natives.AddTextComponentSubstringPlayerName, objString); @@ -146,6 +160,8 @@ private void CallFunctionBase(string function, params object[] parameters) { #if FIVEM API.ScaleformMovieMethodAddParamFloat(objFloat); +#elif ALTV + Alt.Natives.ScaleformMovieMethodAddParamFloat(objFloat); #elif RAGEMP Invoker.Invoke(0xD69736AAE04DB51A, objFloat); #elif RPH @@ -158,6 +174,8 @@ private void CallFunctionBase(string function, params object[] parameters) { #if FIVEM API.ScaleformMovieMethodAddParamFloat((float)objDouble); +#elif ALTV + Alt.Natives.ScaleformMovieMethodAddParamFloat((float)objDouble); #elif RAGEMP Invoker.Invoke(0xD69736AAE04DB51A, (float)objDouble); #elif RPH @@ -170,6 +188,8 @@ private void CallFunctionBase(string function, params object[] parameters) { #if FIVEM API.ScaleformMovieMethodAddParamBool(objBool); +#elif ALTV + Alt.Natives.ScaleformMovieMethodAddParamBool(objBool); #elif RAGEMP Invoker.Invoke(0xC58424BA936EB458, objBool); #elif RPH @@ -187,7 +207,7 @@ private void CallFunctionBase(string function, params object[] parameters) #endregion - #region Public Functions + #region Functions /// /// Checks if the specified Scaleform Return Value is ready to be fetched. @@ -198,6 +218,8 @@ public bool IsValueReady(int id) { #if FIVEM return API.IsScaleformMovieMethodReturnValueReady(id); +#elif ALTV + return Alt.Natives.IsScaleformMovieMethodReturnValueReady(id); #elif RAGEMP return Invoker.Invoke(Natives._0x768FF8961BA904D6, id); #elif RPH @@ -218,6 +240,8 @@ public T GetValue(int id) { #if FIVEM return (T)(object)API.GetScaleformMovieMethodReturnValueString(id); +#elif ALTV + return (T)(object)Alt.Natives.GetScaleformMovieMethodReturnValueString(id); #elif RAGEMP return Invoker.Invoke(0xE1E258829A885245, id); #elif RPH @@ -230,6 +254,8 @@ public T GetValue(int id) { #if FIVEM return (T)(object)API.GetScaleformMovieMethodReturnValueInt(id); +#elif ALTV + return (T)(object)Alt.Natives.GetScaleformMovieMethodReturnValueInt(id); #elif RAGEMP return Invoker.Invoke(0x2DE7EFA66B906036, id); #elif RPH @@ -242,12 +268,14 @@ public T GetValue(int id) { #if FIVEM return (T)(object)API.GetScaleformMovieMethodReturnValueBool(id); +#elif ALTV + return (T)(object)Alt.Natives.GetScaleformMovieMethodReturnValueBool(id); #elif RAGEMP return Invoker.Invoke(0xD80A80346A45D761, id); #elif RPH return (T)(object)NativeFunction.CallByHash(0xD80A80346A45D761, id); #elif SHVDN3 - return (T)(object)Function.Call(Hash._GET_SCALEFORM_MOVIE_METHOD_RETURN_VALUE_BOOL, id); + return (T)(object)Function.Call(Hash.GET_SCALEFORM_MOVIE_METHOD_RETURN_VALUE_BOOL, id); #endif } else @@ -265,6 +293,8 @@ public void CallFunction(string function, params object[] parameters) CallFunctionBase(function, parameters); #if FIVEM API.EndScaleformMovieMethod(); +#elif ALTV + Alt.Natives.EndScaleformMovieMethod(); #elif RAGEMP Invoker.Invoke(0xC6796A8FFA375E53); #elif RPH @@ -311,6 +341,8 @@ public int CallFunctionReturn(string function, params object[] parameters) CallFunctionBase(function, parameters); #if FIVEM return API.EndScaleformMovieMethodReturnValue(); +#elif ALTV + return Alt.Natives.EndScaleformMovieMethodReturnValue(); #elif RAGEMP return Invoker.Invoke(0xC50AA39A577AF886); #elif RPH @@ -335,6 +367,8 @@ public virtual void DrawFullScreen() Update(); #if FIVEM API.DrawScaleformMovieFullscreen(Handle, 255, 255, 255, 255, 0); +#elif ALTV + Alt.Natives.DrawScaleformMovieFullscreen(Handle, 255, 255, 255, 255, 0); #elif RAGEMP Invoker.Invoke(Natives.DrawScaleformMovieFullscreen, Handle, 255, 255, 255, 255, 0); #elif RPH @@ -359,12 +393,22 @@ public void Dispose() int id = Handle; #if FIVEM API.SetScaleformMovieAsNoLongerNeeded(ref id); +#elif ALTV + Alt.Natives.SetScaleformMovieAsNoLongerNeeded(ref id); #elif RAGEMP - Invoker.Invoke(Natives.SetScaleformMovieAsNoLongerNeeded, id); + IntReference idPtr = new IntReference(id); + Invoker.Invoke(Natives.SetScaleformMovieAsNoLongerNeeded, idPtr); #elif RPH - NativeFunction.CallByHash(0x1D132D614DD86811, new NativeArgument(id)); + using (NativePointer idPtr = new NativePointer(4)) + { + idPtr.SetValue(id); + NativeFunction.CallByHash(0x6DD8F5AA635EB4B2, idPtr); + } #elif SHVDN3 - Function.Call(Hash.SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED, new OutputArgument(id)); + using (OutputArgument idPtr = new OutputArgument(id)) + { + Function.Call(Hash.SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED, idPtr); + } #endif } diff --git a/LemonUI/Scaleform/BigMessage.cs b/LemonUI/Scaleform/BigMessage.cs index 24a001c6..ebc4af27 100644 --- a/LemonUI/Scaleform/BigMessage.cs +++ b/LemonUI/Scaleform/BigMessage.cs @@ -6,70 +6,25 @@ using Rage; #elif SHVDN3 using GTA; +#elif ALTV +using AltV.Net.Client; #endif using System; namespace LemonUI.Scaleform { - /// - /// The type for a big message. - /// - public enum MessageType - { - /// - /// A centered message with customizable text an d background colors. - /// Internally called SHOW_SHARD_CENTERED_MP_MESSAGE. - /// - Customizable = 0, - /// - /// Used when you rank up on GTA Online. - /// Internally called SHOW_SHARD_CREW_RANKUP_MP_MESSAGE. - /// - RankUp = 1, - /// - /// The Mission Passed screen on PS3 and Xbox 360. - /// Internally called SHOW_MISSION_PASSED_MESSAGE. - /// - MissionPassedOldGen = 2, - /// - /// The Message Type shown on the Wasted screen. - /// Internally called SHOW_SHARD_WASTED_MP_MESSAGE. - /// - Wasted = 3, - /// - /// Used on the GTA Online Freemode event announcements. - /// Internally called SHOW_PLANE_MESSAGE. - /// - Plane = 4, - /// - /// Development leftover from when GTA Online was Cops and Crooks. - /// Internally called SHOW_BIG_MP_MESSAGE. - /// - CopsAndCrooks = 5, - /// - /// Message shown when the player purchases a weapon. - /// Internally called SHOW_WEAPON_PURCHASED. - /// - Weapon = 6, - /// - /// Unknown where this one is used. - /// Internally called SHOW_CENTERED_MP_MESSAGE_LARGE. - /// - CenteredLarge = 7, - } - /// /// A customizable big message. /// public class BigMessage : BaseScaleform { - #region Constant Fields + #region Constants private const uint unarmed = 0xA2719263; #endregion - #region Private Fields + #region Fields private MessageType type; private uint weaponHash; @@ -77,7 +32,7 @@ public class BigMessage : BaseScaleform #endregion - #region Public Properties + #region Properties /// /// The title of the message. @@ -100,7 +55,7 @@ public class BigMessage : BaseScaleform /// The Rank when the mode is set to Cops and Crooks. /// public string Rank { get; set; } -#if !RAGEMP +#if !RAGEMP && !ALTV /// /// The hash of the Weapon as an enum. /// @@ -196,7 +151,7 @@ public BigMessage(string title, int colorText) : this(title, string.Empty, strin public BigMessage(string title, int colorText, int colorBackground) : this(title, string.Empty, string.Empty, unarmed, colorText, colorBackground, MessageType.Customizable) { } -#if !RAGEMP +#if !RAGEMP && !ALTV /// /// Creates a Weapon Purchase message with a custom text and weapons. /// @@ -254,7 +209,7 @@ public BigMessage(string title, string message, string rank, uint weapon, int co #endregion - #region Public Functions + #region Functions /// /// Updates the Message information in the Scaleform. @@ -325,6 +280,8 @@ public void FadeOut(int time) #if RAGEMP uint currentTime = (uint)Misc.GetGameTimer(); +#elif ALTV + uint currentTime = (uint)Alt.MsPerGameMinute; #elif RPH uint currentTime = Game.GameTime; #else @@ -337,6 +294,8 @@ public override void DrawFullScreen() { #if RAGEMP uint time = (uint)Misc.GetGameTimer(); +#elif ALTV + uint time = (uint)Alt.MsPerGameMinute; #elif RPH uint time = Game.GameTime; #else diff --git a/LemonUI/Scaleform/BruteForce.cs b/LemonUI/Scaleform/BruteForce.cs index 0b0c5a59..b9b9b85a 100644 --- a/LemonUI/Scaleform/BruteForce.cs +++ b/LemonUI/Scaleform/BruteForce.cs @@ -7,6 +7,9 @@ using Rage; using Rage.Native; using Control = Rage.GameControl; +#elif ALTV +using AltV.Net.Client; +using LemonUI.Elements; #elif SHVDN3 using GTA; using GTA.Native; @@ -16,79 +19,6 @@ namespace LemonUI.Scaleform { - /// - /// The Background of the BruteForce Hack Minigame. - /// - public enum BruteForceBackground - { - /// - /// A simple Black background. - /// - Black = 0, - /// - /// A simple Purple background. - /// - Purple = 1, - /// - /// A simple Gray background. - /// - Gray = 2, - /// - /// A simple Light Blue background. - /// - LightBlue = 3, - /// - /// A Light Blue Wallpaper. - /// - Wallpaper1 = 4, - /// - /// A Fade from Gray in the center to Black in the corners. - /// - DarkFade = 5, - } - - /// - /// The status of the BruteForce Hack after finishing. - /// - public enum BruteForceStatus - { - /// - /// The user completed the hack successfully. - /// - Completed = 0, - /// - /// The user ran out of time. - /// - OutOfTime = 1, - /// - /// The player ran out of lives. - /// - OutOfLives = 2, - } - - /// - /// Event information after an the BruteForce hack has finished. - /// - public class BruteForceFinishedEventArgs - { - /// - /// The final status of the Hack. - /// - public BruteForceStatus Status { get; } - - internal BruteForceFinishedEventArgs(BruteForceStatus status) - { - Status = status; - } - } - - /// - /// Represents the method that is called when the end user finishes the BruteForce hack. - /// - /// The source of the event. - /// An with the hack status. - public delegate void BruteForceFinishedEventHandler(object sender, BruteForceFinishedEventArgs e); - /// /// The BruteForce Hacking Minigame shown in multiple missions. /// @@ -130,7 +60,7 @@ public string Word { if (value.Length != 8) { - throw new ArgumentOutOfRangeException("The word needs to be exactly 8 characters long.", nameof(value)); + throw new ArgumentOutOfRangeException(nameof(value), "The word needs to be exactly 8 characters long."); } word = value; CallFunction("SET_ROULETTE_WORD", value); @@ -189,7 +119,7 @@ public int CloseAfter { if (value < -1) { - throw new ArgumentOutOfRangeException("The Closure time can't be under -1.", nameof(value)); + throw new ArgumentOutOfRangeException(nameof(value), "The Closure time can't be under -1."); } closeAfter = value; } @@ -268,6 +198,8 @@ public void Reset() #if RAGEMP int time = Misc.GetGameTimer(); +#elif ALTV + int time = Alt.MsPerGameMinute; #elif RPH uint time = Game.GameTime; #else @@ -285,7 +217,7 @@ public void SetColumnSpeed(int index, float speed) { if (index >= 8 || index < 0) { - throw new ArgumentOutOfRangeException("The index needs to be between 0 and 7.", nameof(index)); + throw new ArgumentOutOfRangeException(nameof(index), "The index needs to be between 0 and 7."); } CallFunction("SET_COLUMN_SPEED", index, speed); } @@ -304,6 +236,8 @@ public override void Update() { #if RAGEMP int time = Misc.GetGameTimer(); +#elif ALTV + int time = Alt.MsPerGameMinute; #elif RPH uint time = Game.GameTime; #else diff --git a/LemonUI/Scaleform/BruteForceBackground.cs b/LemonUI/Scaleform/BruteForceBackground.cs new file mode 100644 index 00000000..b5233302 --- /dev/null +++ b/LemonUI/Scaleform/BruteForceBackground.cs @@ -0,0 +1,33 @@ +namespace LemonUI.Scaleform +{ + /// + /// The Background of the BruteForce Hack Minigame. + /// + public enum BruteForceBackground + { + /// + /// A simple Black background. + /// + Black = 0, + /// + /// A simple Purple background. + /// + Purple = 1, + /// + /// A simple Gray background. + /// + Gray = 2, + /// + /// A simple Light Blue background. + /// + LightBlue = 3, + /// + /// A Light Blue Wallpaper. + /// + Wallpaper1 = 4, + /// + /// A Fade from Gray in the center to Black in the corners. + /// + DarkFade = 5, + } +} diff --git a/LemonUI/Scaleform/BruteForceFinishedEventArgs.cs b/LemonUI/Scaleform/BruteForceFinishedEventArgs.cs new file mode 100644 index 00000000..8143f77e --- /dev/null +++ b/LemonUI/Scaleform/BruteForceFinishedEventArgs.cs @@ -0,0 +1,26 @@ +namespace LemonUI.Scaleform +{ + /// + /// Event information after an the BruteForce hack has finished. + /// + public class BruteForceFinishedEventArgs + { + #region Properties + + /// + /// The final status of the Hack. + /// + public BruteForceStatus Status { get; } + + #endregion + + #region Constructors + + internal BruteForceFinishedEventArgs(BruteForceStatus status) + { + Status = status; + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/BruteForceFinishedEventHandler.cs b/LemonUI/Scaleform/BruteForceFinishedEventHandler.cs new file mode 100644 index 00000000..3424ea1b --- /dev/null +++ b/LemonUI/Scaleform/BruteForceFinishedEventHandler.cs @@ -0,0 +1,10 @@ +namespace LemonUI.Scaleform +{ + + /// + /// Represents the method that is called when the end user finishes the BruteForce hack. + /// + /// The source of the event. + /// An with the hack status. + public delegate void BruteForceFinishedEventHandler(object sender, BruteForceFinishedEventArgs e); +} diff --git a/LemonUI/Scaleform/BruteForceStatus.cs b/LemonUI/Scaleform/BruteForceStatus.cs new file mode 100644 index 00000000..99f959d2 --- /dev/null +++ b/LemonUI/Scaleform/BruteForceStatus.cs @@ -0,0 +1,21 @@ +namespace LemonUI.Scaleform +{ + /// + /// The status of the BruteForce Hack after finishing. + /// + public enum BruteForceStatus + { + /// + /// The user completed the hack successfully. + /// + Completed = 0, + /// + /// The user ran out of time. + /// + OutOfTime = 1, + /// + /// The player ran out of lives. + /// + OutOfLives = 2, + } +} diff --git a/LemonUI/Scaleform/Celebration.cs b/LemonUI/Scaleform/Celebration.cs new file mode 100644 index 00000000..385469c8 --- /dev/null +++ b/LemonUI/Scaleform/Celebration.cs @@ -0,0 +1,219 @@ +#if ALTV +using AltV.Net.Client; +#elif FIVEM +using CitizenFX.Core; +using CitizenFX.Core.Native; +#elif RAGEMP +using RAGE.Game; +#elif RPH +using Rage; +using Rage.Native; +#elif SHVDN3 +using GTA; +using GTA.Native; +#endif +using System; + +namespace LemonUI.Scaleform +{ + /// + /// The foreground of the celebration scaleform. + /// + public class Celebration : CelebrationCore + { + #region Fields + + private long showUntil = 0; + private bool cancel = false; + + #endregion + + #region Properties + + /// + /// The background of the scaleform. + /// + public CelebrationBackground Background { get; } = new CelebrationBackground(); + /// + /// The foreground of the scaleform. + /// + public CelebrationForeground Foreground { get; } = new CelebrationForeground(); + /// + /// The mode name shown. + /// + /// + /// This is used to show the current mode, like "HEIST", "RACE", "LAST TEAM STANDING", etc. + /// + public string Mode { get; set; } = string.Empty; + /// + /// The job name shown. + /// + /// + /// This is used to show the current job name like "The Prison Break" or "Premium Race - East Coast". + /// + public string Job { get; set; } = string.Empty; + /// + /// The challenge shown. + /// + /// + /// This is used to show messages like "ROUND 10" or "POTENTIAL CUT $1000000". + /// + public string Challenge { get; set; } = string.Empty; + /// + /// For how long the scalefom is show. + /// + public int Duration { get; set; } = 2; + /// + /// The style of the celebration. + /// + public CelebrationStyle Style { get; set; } = CelebrationStyle.Clean; + + #endregion + + #region Events + + /// + /// Event triggered when the scaleform is shown on the screen. + /// + public event EventHandler Shown; + /// + /// Event triggered when the scaleform has finished fading out. + /// + public event EventHandler Finished; + + #endregion + + #region Constructors + + /// + /// Initializes a new Celebration scaleform. + /// + public Celebration() : base("MP_CELEBRATION") + { + } + + #endregion + + #region Tools + + private void CallFunctionOnAll(string function, params object[] parameters) + { + Background.CallFunction(function, parameters); + Foreground.CallFunction(function, parameters); + CallFunction(function, parameters); + } + + #endregion + + #region Functions + + /// + /// Shows the celebration scaleform. + /// + public void Show() + { + cancel = false; + Visible = true; + + const string wallId = "intro"; + + CallFunctionOnAll("CLEANUP", wallId); + CallFunctionOnAll("CREATE_STAT_WALL", wallId, "HUD_COLOUR_BLACK", 40); + + CallFunctionOnAll("SET_PAUSE_DURATION", Duration); + // challengeTextLabel appears to be used as a bool and challengePartsText is appended + CallFunctionOnAll("ADD_INTRO_TO_WALL", wallId, Mode, Job, true, Challenge, string.Empty, Challenge, Duration, string.Empty, true, "HUD_COLOUR_WHITE"); + CallFunctionOnAll("ADD_BACKGROUND_TO_WALL", wallId, 75, (int)Style); + CallFunctionOnAll("SHOW_STAT_WALL", wallId); + + Shown?.Invoke(this, EventArgs.Empty); + + // Explanation for future me + // 333ms going in + // 333ms going out +#if ALTV + int time = Alt.Natives.GetGameTimer(); +#elif RAGEMP + int time = Misc.GetGameTimer(); +#elif RPH + uint time = Game.GameTime; +#elif FIVEM || SHVDN3 + int time = Game.GameTime; +#endif + showUntil = time + 333 + 333 + (Duration * 1000); + } + /// + /// Cancels the current screen being shown. + /// + public void Cancel() + { + if (Visible) + { + cancel = true; + } + } + /// + public override void Process() + { + if (!Visible) + { + return; + } + + if (cancel) + { + showUntil = -1; + Visible = false; + return; + } + + DrawFullScreen(); + +#if ALTV + int time = Alt.Natives.GetGameTimer(); +#elif RAGEMP + int time = Misc.GetGameTimer(); +#elif RPH + uint time = Game.GameTime; +#elif FIVEM || SHVDN3 + int time = Game.GameTime; +#endif + + if (showUntil < time) + { + showUntil = 0; + Visible = false; + Finished?.Invoke(this, EventArgs.Empty); + } + } + /// + /// Draws the celebration scaleform. + /// + public override void DrawFullScreen() + { + if (!Visible) + { + return; + } + + #if ALTV + Alt.Natives.DrawScaleformMovieFullscreenMasked(Background.Handle, Foreground.Handle, 255, 255, 255, 255); + Alt.Natives.DrawScaleformMovieFullscreen(Handle, 255, 255, 255, 255, 255); + #elif FIVEM + API.DrawScaleformMovieFullscreenMasked(Background.Handle, Foreground.Handle, 255, 255, 255, 255); + API.DrawScaleformMovieFullscreen(Handle, 255, 255, 255, 255, 255); + #elif RAGEMP + Invoker.Invoke(Natives.DrawScaleformMovieFullscreenMasked, Background.Handle, Foreground.Handle, 255, 255, 255, 255); + Invoker.Invoke(Natives.DrawScaleformMovieFullscreen, Handle, 255, 255, 255, 255); + #elif RPH + NativeFunction.CallByHash(0xCF537FDE4FBD4CE5, Background.Handle, Foreground.Handle, 255, 255, 255, 255); + NativeFunction.CallByHash(0x0DF606929C105BE1, Handle, 255, 255, 255, 255); + #elif SHVDN3 + Function.Call(Hash.DRAW_SCALEFORM_MOVIE_FULLSCREEN_MASKED, Background.Handle, Foreground.Handle, 255, 255, 255, 255); + Function.Call(Hash.DRAW_SCALEFORM_MOVIE_FULLSCREEN, Handle, 255, 255, 255, 255); + #endif + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/CelebrationBackground.cs b/LemonUI/Scaleform/CelebrationBackground.cs new file mode 100644 index 00000000..512b618c --- /dev/null +++ b/LemonUI/Scaleform/CelebrationBackground.cs @@ -0,0 +1,19 @@ +namespace LemonUI.Scaleform +{ + /// + /// The background of the celebration scaleform. + /// + public class CelebrationBackground : CelebrationCore + { + #region Constructors + + /// + /// Initializes a new Celebration background. + /// + public CelebrationBackground() : base("MP_CELEBRATION_BG") + { + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/CelebrationCore.cs b/LemonUI/Scaleform/CelebrationCore.cs new file mode 100644 index 00000000..7377fc73 --- /dev/null +++ b/LemonUI/Scaleform/CelebrationCore.cs @@ -0,0 +1,31 @@ +namespace LemonUI.Scaleform +{ + /// + /// The base of all MP_CELEBRATION* scaleforms. + /// + public abstract class CelebrationCore : BaseScaleform + { + #region Constructors + + /// + /// Initializes a new class with the core behavior of the Celebration scaleform. + /// + /// The scaleform to use. + public CelebrationCore(string sc) : base(sc) + { + } + + #endregion + + #region Functions + + /// + /// Updates the celebration scaleform. + /// + public override void Update() + { + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/CelebrationForeground.cs b/LemonUI/Scaleform/CelebrationForeground.cs new file mode 100644 index 00000000..f90274ff --- /dev/null +++ b/LemonUI/Scaleform/CelebrationForeground.cs @@ -0,0 +1,19 @@ +namespace LemonUI.Scaleform +{ + /// + /// The foreground of the celebration scaleform. + /// + public class CelebrationForeground : CelebrationCore + { + #region Constructors + + /// + /// Initializes a new Celebration foreground. + /// + public CelebrationForeground() : base("MP_CELEBRATION_FG") + { + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/CelebrationStyle.cs b/LemonUI/Scaleform/CelebrationStyle.cs new file mode 100644 index 00000000..121fe525 --- /dev/null +++ b/LemonUI/Scaleform/CelebrationStyle.cs @@ -0,0 +1,25 @@ +namespace LemonUI.Scaleform +{ + /// + /// The style of the Celebration scaleform. + /// + public enum CelebrationStyle + { + /// + /// General purpose clean style. used in missions. + /// + Clean = 0, + /// + /// The style used in the heist prep missions. + /// + Prep = 1, + /// + /// The style used in the heist finals and end of prep/final. + /// + Heist = 2, + /// + /// The style used for the Stunt Races. + /// + Race = 3 + } +} diff --git a/LemonUI/Scaleform/Countdown.cs b/LemonUI/Scaleform/Countdown.cs new file mode 100644 index 00000000..1484dcc7 --- /dev/null +++ b/LemonUI/Scaleform/Countdown.cs @@ -0,0 +1,194 @@ +#if ALTV +using AltV.Net.Client; +#elif FIVEM +using CitizenFX.Core; +#elif RAGEMP +using RAGE.Game; +#elif RPH +using Rage; +#elif SHVDN3 +using GTA; +#endif +using System; + +namespace LemonUI.Scaleform +{ + /// + /// The Countdown scaleform in the GTA Online races. + /// + public class Countdown : BaseScaleform + { + #region Fields + + private int duration = 3; + private long lastStepTime = 0; + + #endregion + + #region Defaults + + // TODO: Add the Stunt Race sounds, Countdown_1 and Countdown_GO in DLC_AW_Frontend_Sounds + // TODO: See why Countdown_GO doesn't plays correctly + + /// + /// The default sound played when the countdown + /// + public static Sound DefaultCountSound = new Sound("HUD_MINI_GAME_SOUNDSET", "CHECKPOINT_NORMAL"); + /// + /// The default sound when th + /// + public static Sound DefaultGoSound = new Sound("HUD_MINI_GAME_SOUNDSET", "GO"); + + #endregion + + #region Properties + + /// + /// The sound played when counting down. + /// + public Sound CountSound { get; set; } = DefaultCountSound; + /// + /// The sound played when the countdown has finished. + /// + public Sound GoSound { get; set; } = DefaultGoSound; + /// + /// The duration of the countdown. + /// + public int Duration + { + get => duration; + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "The duration can't be equal or under zero."); + } + + duration = value; + } + } + /// + /// The current count. + /// + public int Current { get; private set; } + + #endregion + + #region Events + + /// + /// Event triggered when the countdown starts. + /// + public event EventHandler Started; + /// + /// Event triggered when the countdown has finished. + /// + public event EventHandler Finished; + + #endregion + + #region Constructors + + /// + /// Creates a new countdown scaleform. + /// + public Countdown() : base("COUNTDOWN") + { + } + + #endregion + + #region Tools + + private void ShowStep(int step) + { + string asString = step == 0 ? "GO" : step.ToString(); + + CallFunction("SET_MESSAGE", asString, 255, 255, 255, true); + CallFunction("FADE_MP", asString, 255, 255, 255); + + if (step == 0) + { + GoSound?.PlayFrontend(); + } + else + { + CountSound?.PlayFrontend(); + } + } + + #endregion + + #region Functions + + /// + /// Starts the countdown. + /// + public void Start() + { + Visible = true; + +#if ALTV + lastStepTime = Alt.Natives.GetGameTimer(); +#elif RAGEMP + lastStepTime = Misc.GetGameTimer(); +#elif RPH + lastStepTime = Game.GameTime; +#elif FIVEM || SHVDN3 + lastStepTime = Game.GameTime; +#endif + + Current = duration; + ShowStep(Current); + Started?.Invoke(this, EventArgs.Empty); + } + /// + public override void Process() + { + if (!Visible) + { + return; + } + + if (lastStepTime > 0) + { +#if ALTV + int currentTime = Alt.Natives.GetGameTimer(); +#elif RAGEMP + int currentTime = Misc.GetGameTimer(); +#elif RPH + uint currentTime = Game.GameTime; +#elif FIVEM || SHVDN3 + int currentTime = Game.GameTime; +#endif + + if (currentTime - lastStepTime >= 1000) + { + if (Current == 0) + { + lastStepTime = 0; + Visible = false; + return; + } + + lastStepTime = currentTime; + Current--; + ShowStep(Current); + + if (Current == 0) + { + Finished?.Invoke(this, EventArgs.Empty); + } + } + } + + DrawFullScreen(); + } + /// + public override void Update() + { + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/IScaleform.cs b/LemonUI/Scaleform/IScaleform.cs index 7b10937a..3c3faa4d 100644 --- a/LemonUI/Scaleform/IScaleform.cs +++ b/LemonUI/Scaleform/IScaleform.cs @@ -7,9 +7,13 @@ namespace LemonUI.Scaleform /// public interface IScaleform : IDrawable, IProcessable, IDisposable { + #region Properties + /// /// Draws the Scaleform in full screen. /// void DrawFullScreen(); + + #endregion } } diff --git a/LemonUI/Scaleform/InstructionalButton.cs b/LemonUI/Scaleform/InstructionalButton.cs new file mode 100644 index 00000000..d0ebd42b --- /dev/null +++ b/LemonUI/Scaleform/InstructionalButton.cs @@ -0,0 +1,112 @@ +#if FIVEM +using CitizenFX.Core; +using CitizenFX.Core.Native; +#elif RAGEMP +using RAGE.Game; +#elif ALTV +using AltV.Net.Client; +using LemonUI.Elements; +#elif RPH +using Rage.Native; +using Control = Rage.GameControl; +#elif SHVDN3 +using GTA; +using GTA.Native; +#endif + +namespace LemonUI.Scaleform +{ + /// + /// An individual instructional button. + /// + public struct InstructionalButton + { + #region Fields + + private Control control; + private string raw; + + #endregion + + #region Properties + + /// + /// The description of this button. + /// + public string Description { get; set; } + /// + /// The Control used by this button. + /// + public Control Control + { + get => control; + set + { + control = value; +#if FIVEM + raw = API.GetControlInstructionalButton(2, (int)value, 1); +#elif RAGEMP + raw = Invoker.Invoke(Natives.GetControlInstructionalButton, 2, (int)value, 1); +#elif RPH + raw = (string)NativeFunction.CallByHash(0x0499D7B09FC9B407, typeof(string), 2, (int)control, 1); +#elif SHVDN3 + raw = Function.Call(Hash.GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING, 2, (int)value, 1); +#elif ALTV + raw = Alt.Natives.GetControlInstructionalButtonsString(2, (int)value, true); +#endif + } + } + /// + /// The Raw Control sent to the Scaleform. + /// + public string Raw + { + get => raw; + set + { + raw = value; + control = (Control)(-1); + } + } + + #endregion + + #region Constructors + + /// + /// Creates an instructional button for a Control. + /// + /// The text for the description. + /// The control to use. + public InstructionalButton(string description, Control control) + { + Description = description; + this.control = control; +#if FIVEM + raw = API.GetControlInstructionalButton(2, (int)control, 1); +#elif ALTV + raw = Alt.Natives.GetControlInstructionalButtonsString(2, (int)control, true); +#elif RAGEMP + raw = Invoker.Invoke(Natives.GetControlInstructionalButton, 2, (int)control, 1); +#elif RPH + raw = (string)NativeFunction.CallByHash(0x0499D7B09FC9B407, typeof(string), 2, (int)control, 1); +#elif SHVDN3 + raw = Function.Call(Hash.GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING, 2, (int)control, 1); +#endif + } + + /// + /// Creates an instructional button for a raw control. + /// + /// The text for the description. + /// The raw value of the control. + public InstructionalButton(string description, string raw) + { + Description = description; + control = (Control)(-1); + this.raw = raw; + } + + #endregion + } +} diff --git a/LemonUI/Scaleform/InstructionalButtons.cs b/LemonUI/Scaleform/InstructionalButtons.cs index 649db19c..8ef34a50 100644 --- a/LemonUI/Scaleform/InstructionalButtons.cs +++ b/LemonUI/Scaleform/InstructionalButtons.cs @@ -15,102 +15,13 @@ namespace LemonUI.Scaleform { - /// - /// An individual instructional button. - /// - public struct InstructionalButton - { - #region Private Fields - - private Control control; - private string raw; - - #endregion - - #region Public Properties - - /// - /// The description of this button. - /// - public string Description { get; set; } - /// - /// The Control used by this button. - /// - public Control Control - { - get => control; - set - { - control = value; -#if FIVEM - raw = API.GetControlInstructionalButton(2, (int)value, 1); -#elif RAGEMP - raw = Invoker.Invoke(Natives.GetControlInstructionalButton, 2, (int)value, 1); -#elif RPH - raw = (string)NativeFunction.CallByHash(0x0499D7B09FC9B407, typeof(string), 2, (int)control, 1); -#elif SHVDN3 - raw = Function.Call(Hash.GET_CONTROL_INSTRUCTIONAL_BUTTON, 2, (int)value, 1); -#endif - } - } - /// - /// The Raw Control sent to the Scaleform. - /// - public string Raw - { - get => raw; - set - { - raw = value; - control = (Control)(-1); - } - } - - #endregion - - #region Constructor - - /// - /// Creates an instructional button for a Control. - /// - /// The text for the description. - /// The control to use. - public InstructionalButton(string description, Control control) - { - Description = description; - this.control = control; -#if FIVEM - raw = API.GetControlInstructionalButton(2, (int)control, 1); -#elif RAGEMP - raw = Invoker.Invoke(Natives.GetControlInstructionalButton, 2, (int)control, 1); -#elif RPH - raw = (string)NativeFunction.CallByHash(0x0499D7B09FC9B407, typeof(string), 2, (int)control, 1); -#elif SHVDN3 - raw = Function.Call(Hash.GET_CONTROL_INSTRUCTIONAL_BUTTON, 2, (int)control, 1); -#endif - } - - /// - /// Creates an instructional button for a raw control. - /// - /// The text for the description. - /// The raw value of the control. - public InstructionalButton(string description, string raw) - { - Description = description; - control = (Control)(-1); - this.raw = raw; - } - - #endregion - } /// /// Buttons shown on the bottom right of the screen. /// public class InstructionalButtons : BaseScaleform { - #region Public Fields + #region Fields /// /// The buttons used in this Scaleform. @@ -132,7 +43,7 @@ public InstructionalButtons(params InstructionalButton[] buttons) : base("INSTRU #endregion - #region Public Functions + #region Functions /// /// Adds an Instructional Button. diff --git a/LemonUI/Scaleform/LoadingScreen.cs b/LemonUI/Scaleform/LoadingScreen.cs index 1d580dba..a4e25bcc 100644 --- a/LemonUI/Scaleform/LoadingScreen.cs +++ b/LemonUI/Scaleform/LoadingScreen.cs @@ -5,7 +5,7 @@ namespace LemonUI.Scaleform /// public class LoadingScreen : BaseScaleform { - #region Public Properties + #region Properties /// /// The title of the loading screen. @@ -66,7 +66,7 @@ public LoadingScreen(string title, string subtitle, string description, string d #endregion - #region Public Functions + #region Functions /// /// Changes the texture shown on the loading screen. diff --git a/LemonUI/Scaleform/MessageType.cs b/LemonUI/Scaleform/MessageType.cs new file mode 100644 index 00000000..0a65930e --- /dev/null +++ b/LemonUI/Scaleform/MessageType.cs @@ -0,0 +1,49 @@ +namespace LemonUI.Scaleform +{ + /// + /// The type for a big message. + /// + public enum MessageType + { + /// + /// A centered message with customizable text an d background colors. + /// Internally called SHOW_SHARD_CENTERED_MP_MESSAGE. + /// + Customizable = 0, + /// + /// Used when you rank up on GTA Online. + /// Internally called SHOW_SHARD_CREW_RANKUP_MP_MESSAGE. + /// + RankUp = 1, + /// + /// The Mission Passed screen on PS3 and Xbox 360. + /// Internally called SHOW_MISSION_PASSED_MESSAGE. + /// + MissionPassedOldGen = 2, + /// + /// The Message Type shown on the Wasted screen. + /// Internally called SHOW_SHARD_WASTED_MP_MESSAGE. + /// + Wasted = 3, + /// + /// Used on the GTA Online Freemode event announcements. + /// Internally called SHOW_PLANE_MESSAGE. + /// + Plane = 4, + /// + /// Development leftover from when GTA Online was Cops and Crooks. + /// Internally called SHOW_BIG_MP_MESSAGE. + /// + CopsAndCrooks = 5, + /// + /// Message shown when the player purchases a weapon. + /// Internally called SHOW_WEAPON_PURCHASED. + /// + Weapon = 6, + /// + /// Unknown where this one is used. + /// Internally called SHOW_CENTERED_MP_MESSAGE_LARGE. + /// + CenteredLarge = 7, + } +} diff --git a/LemonUI/Screen.cs b/LemonUI/Screen.cs index 948d6b69..b4f79204 100644 --- a/LemonUI/Screen.cs +++ b/LemonUI/Screen.cs @@ -12,6 +12,9 @@ using GTA; using GTA.Native; using GTA.UI; +#elif ALTV +using AltV.Net.Client; +using LemonUI.Elements; #endif using LemonUI.Extensions; using System; @@ -19,38 +22,13 @@ namespace LemonUI { - /// - /// Represents the internal alignment of screen elements. - /// - public enum GFXAlignment - { - /// - /// Vertical Alignment to the Bottom. - /// - Bottom = 66, - /// - /// Vertical Alignment to the Top. - /// - Top = 84, - /// - /// Centered Vertically or Horizontally. - /// - Center = 67, - /// - /// Horizontal Alignment to the Left. - /// - Left = 76, - /// - /// Horizontal Alignment to the Right. - /// - Right = 82, - } - /// /// Contains a set of tools to work with the screen information. /// public static class Screen { + #region Properties + /// /// The Aspect Ratio of the screen resolution. /// @@ -65,10 +43,28 @@ public static float AspectRatio #elif RPH return NativeFunction.CallByHash(0xF1307EF624A80D87, false); #elif SHVDN3 - return Function.Call(Hash._GET_ASPECT_RATIO, false); + return Function.Call(Hash.GET_ASPECT_RATIO, false); +#elif ALTV + return Alt.Natives.GetAspectRatio(false); #endif } } + +#if ALTV + /// + /// 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); + } + } +#endif + /// /// The location of the cursor on screen between 0 and 1. /// @@ -79,6 +75,9 @@ public static PointF CursorPositionRelative #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); @@ -93,6 +92,10 @@ public static PointF CursorPositionRelative } } + #endregion + + #region Functions + /// /// Converts a relative resolution into one scaled to 1080p. /// @@ -177,6 +180,8 @@ public static PointF GetRealPosition(float x, float y) 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(); @@ -184,19 +189,21 @@ public static PointF GetRealPosition(float x, float y) realX = argX.Value; realY = argY.Value; #elif RPH - using (NativePointer argX = new NativePointer()) - using (NativePointer argY = new NativePointer()) + 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 - OutputArgument argX = new OutputArgument(); - OutputArgument argY = new OutputArgument(); - Function.Call((Hash)0x6DD8F5AA635EB4B2, relativeX, relativeY, argX, argY); // _GET_SCRIPT_GFX_POSITION - realX = argX.GetResult(); - realY = argY.GetResult(); + 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); @@ -209,12 +216,14 @@ 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 - Function.Call(Hash._SET_MOUSE_CURSOR_ACTIVE_THIS_FRAME); + Function.Call(Hash.SET_MOUSE_CURSOR_THIS_FRAME); #endif } /// @@ -254,6 +263,9 @@ public static void SetElementAlignment(GFXAlignment horizontal, GFXAlignment ver #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); @@ -272,6 +284,8 @@ public static void ResetElementAlignment() { #if FIVEM API.ResetScriptGfxAlign(); +#elif ALTV + Alt.Natives.ResetScriptGfxAlign(); #elif RAGEMP Invoker.Invoke(0xE3A3DB414A373DAB); #elif RPH @@ -280,5 +294,7 @@ public static void ResetElementAlignment() Function.Call(Hash.RESET_SCRIPT_GFX_ALIGN); #endif } + + #endregion } } diff --git a/LemonUI/Sound.cs b/LemonUI/Sound.cs index f1e6f348..61322334 100644 --- a/LemonUI/Sound.cs +++ b/LemonUI/Sound.cs @@ -9,6 +9,9 @@ #elif SHVDN3 using GTA; using GTA.Native; +#elif ALTV +using AltV.Net.Client; +using AltV.Net.Client.Elements.Entities; #endif namespace LemonUI @@ -68,6 +71,9 @@ public void PlayFrontend(bool release) #elif RAGEMP Id = Invoker.Invoke(Natives.GetSoundId); Invoker.Invoke(Natives.PlaySoundFrontend, Id, File, Set, true); +#elif ALTV + Id = Alt.Natives.GetSoundId(); + Alt.Natives.PlaySoundFrontend(Id, File, Set, true); #elif RPH Id = NativeFunction.CallByHash(0x430386FE9BF80B45); NativeFunction.CallByHash(0x67C540AA08E4A6F5, Id, File, Set, true); @@ -97,6 +103,8 @@ public void Stop() Invoker.Invoke(Natives.StopSound, Id); #elif RPH NativeFunction.CallByHash(0xA3B0C41BA5CC0BB5, Id); +#elif ALTV + Alt.Natives.StopSound(Id); #elif SHVDN3 Function.Call(Hash.STOP_SOUND, Id); #endif @@ -118,6 +126,8 @@ public void Release() Invoker.Invoke(Natives.ReleaseSoundId, Id); #elif RPH NativeFunction.CallByHash(0x353FC880830B88FA, Id); +#elif ALTV + Alt.Natives.ReleaseSoundId(Id); #elif SHVDN3 Function.Call(Hash.RELEASE_SOUND_ID, Id); #endif diff --git a/LemonUI/TimerBars/TimerBar.cs b/LemonUI/TimerBars/TimerBar.cs index 9c44f9fe..9faa9022 100644 --- a/LemonUI/TimerBars/TimerBar.cs +++ b/LemonUI/TimerBars/TimerBar.cs @@ -15,7 +15,7 @@ namespace LemonUI.TimerBars /// public class TimerBar : IDrawable { - #region Constant Fields + #region Fields /// /// The separation between the different timer bars. @@ -30,28 +30,17 @@ public class TimerBar : IDrawable /// internal const float backgroundHeight = 37; - #endregion - - #region Private Fields - - private string rawTitle = string.Empty; - private string rawInfo = string.Empty; - - #endregion - - #region Internal Fields - /// /// The background of the timer bar. /// - internal protected readonly ScaledTexture background = new ScaledTexture("timerbars", "all_black_bg") + protected internal readonly ScaledTexture background = new ScaledTexture("timerbars", "all_black_bg") { Color = Color.FromArgb(160, 255, 255, 255) }; /// /// The title of the timer bar. /// - internal protected readonly ScaledText title = new ScaledText(PointF.Empty, string.Empty, 0.29f) + protected internal readonly ScaledText title = new ScaledText(PointF.Empty, string.Empty, 0.29f) { Alignment = Alignment.Right, WordWrap = 1000 @@ -59,15 +48,18 @@ public class TimerBar : IDrawable /// /// The information of the Timer Bar. /// - internal protected readonly ScaledText info = new ScaledText(PointF.Empty, string.Empty, 0.5f) + protected internal readonly ScaledText info = new ScaledText(PointF.Empty, string.Empty, 0.5f) { Alignment = Alignment.Right, WordWrap = 1000 }; + private string rawTitle = string.Empty; + private string rawInfo = string.Empty; + #endregion - #region Public Properties + #region Properties /// /// The title of the bar, shown on the left. @@ -123,7 +115,7 @@ public TimerBar(string title, string info) #endregion - #region Public Functions + #region Functions /// /// Recalculates the position of the timer bar elements based on the location of it on the screen. diff --git a/LemonUI/TimerBars/TimerBarCollection.cs b/LemonUI/TimerBars/TimerBarCollection.cs index f2c28fc4..f506417c 100644 --- a/LemonUI/TimerBars/TimerBarCollection.cs +++ b/LemonUI/TimerBars/TimerBarCollection.cs @@ -7,10 +7,13 @@ using Rage.Native; #elif SHVDN3 using GTA.UI; +#elif ALTV +using AltV.Net.Client; #endif using System; using System.Collections.Generic; using System.Drawing; +using LemonUI.Elements; namespace LemonUI.TimerBars { @@ -64,7 +67,7 @@ public TimerBarCollection(params TimerBar[] bars) #endregion - #region Public Functions + #region Functions /// /// Adds a onto this collection. @@ -175,6 +178,10 @@ public void Process() NativeFunction.CallByHash(0x6806C51AD12B83B8, 7); NativeFunction.CallByHash(0x6806C51AD12B83B8, 9); NativeFunction.CallByHash(0x6806C51AD12B83B8, 6); +#elif ALTV + Alt.Natives.HideHudComponentThisFrame(7); + Alt.Natives.HideHudComponentThisFrame(9); + Alt.Natives.HideHudComponentThisFrame(6); #elif SHVDN3 Hud.HideComponentThisFrame(HudComponent.AreaName); Hud.HideComponentThisFrame(HudComponent.StreetName); diff --git a/LemonUI/TimerBars/TimerBarProgress.cs b/LemonUI/TimerBars/TimerBarProgress.cs index cde0e06f..b218decb 100644 --- a/LemonUI/TimerBars/TimerBarProgress.cs +++ b/LemonUI/TimerBars/TimerBarProgress.cs @@ -9,39 +9,35 @@ namespace LemonUI.TimerBars /// public class TimerBarProgress : TimerBar { - #region Constant Fields + #region Constants private const float barWidth = 108; private const float barHeight = 15; #endregion - #region Private Fields - - private float progress = 100; - - #endregion - - #region Internal Fields + #region Fields /// /// The background of the Progress Bar. /// - internal protected readonly ScaledRectangle barBackground = new ScaledRectangle(PointF.Empty, SizeF.Empty) + protected internal readonly ScaledRectangle barBackground = new ScaledRectangle(PointF.Empty, SizeF.Empty) { Color = Color.FromArgb(255, 139, 0, 0) }; /// /// The foreground of the Progress Bar. /// - internal protected readonly ScaledRectangle barForeground = new ScaledRectangle(PointF.Empty, SizeF.Empty) + protected internal readonly ScaledRectangle barForeground = new ScaledRectangle(PointF.Empty, SizeF.Empty) { Color = Color.FromArgb(255, 255, 0, 0) }; + private float progress = 100; + #endregion - #region Public Properties + #region Properties /// /// The progress of the bar. @@ -90,7 +86,7 @@ public TimerBarProgress(string title) : base(title, string.Empty) #endregion - #region Public Functions + #region Functions /// /// Recalculates the position of the timer bar elements based on the location of it on the screen. diff --git a/README.md b/README.md index 8259b4ee..d41a970c 100644 --- a/README.md +++ b/README.md @@ -15,37 +15,47 @@ Special thanks to: ## Download -* [GitHub](https://github.com/justalemon/LemonUI/releases) * [5mods](https://www.gta5-mods.com/scripts/lemonui) -* [AppVeyor](https://ci.appveyor.com/project/justalemon/lemonui) (experimental) +* [GitHub Releases](https://github.com/LemonUIbyLemon/LemonUI/releases) +* [GitHub Actions](https://github.com/LemonUIbyLemon/LemonUI/actions) (experimental versions) ## Installation +> Warning: You don't need to install all of the files. You only need to install the ones for the framework you plan to use. For example, if you want to install SHVDN mods, you don't need to install the RPH version. + ### FiveM You don't need to install any files when using FiveM. When you connect to a server, the resources that need it will automatically provide a copy of LemonUI. -### RPH +### RageMP + +You don't need to install any files when using RageMP. When you connect to a server, the resources that need it will automatically provide a copy of LemonUI when compiling the code. + +### RagePluginHook Copy all of the files from the **RPH** folder inside of the compressed file to the root of your GTA V installation directory. -### ScriptHookVDotNet 2 +### ScriptHookVDotNet 2 and ScriptHookVDotNet 3 **PLEASE NOTE THAT THE LAST VERSION THAT SUPPORTED SHVDN2 WAS 1.5.2. [You can download it here]().** -Copy all of the files from the **SHVDN2** folder inside of the compressed file to your **scripts** directory. +Copy all of the files from the **SHVDN2** and/or **SHVDN3** folder(s) inside of the compressed file to your **scripts** directory. + +### Developers + +Add any of the NuGet packages linked above and start working in your IDE. -### ScriptHookVDotNet 3 +If you are using RagePluginHook or ScriptHookVDotNet, you can disable the copy of the dll in your IDE so your users always have to use the latest version available. -Copy all of the files from the **SHVDN3** folder inside of the compressed file to your **scripts** directory. +If you are using RageMP, you will need to download the latest release and copy **LemonUI.RageMP.cs** to you client solution. ## Usage Once installed, the mods that require LemonUI will start working. -If you are a developer, check the [wiki](https://github.com/justalemon/LemonUI/wiki) for information to implement LemonUI in your mod. +If you are a developer, check the [wiki](https://github.com/LemonUIbyLemon/LemonUI/wiki) for information to implement LemonUI in your mod. -[actions-img]: https://img.shields.io/github/workflow/status/LemonUIbyLemon/LemonUI/Compile%20Mod?label=github%20actions +[actions-img]: https://img.shields.io/github/actions/workflow/status/LemonUIbyLemon/LemonUI/main.yml?branch=master&label=actions [actions-url]: https://github.com/LemonUIbyLemon/LemonUI/actions [nuget-img-2]: https://img.shields.io/nuget/v/LemonUI.SHVDN2?label=nuget%20%28shvdn%202%29 [nuget-url-2]: https://www.nuget.org/packages/LemonUI.SHVDN2/ diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..888d68af --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,6 @@ +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site diff --git a/docs/api/.gitignore b/docs/api/.gitignore new file mode 100644 index 00000000..387d3faf --- /dev/null +++ b/docs/api/.gitignore @@ -0,0 +1,2 @@ +*.yml +.manifest diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..822ec1a0 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,7 @@ +# LemonUI API + +Welcome to the LemonUI API! + +You can click the individual namespaces on the left, and the + sign will show the clases available in said namespace. + +Something is missing? [Feel free to open a GitHub Issue](https://github.com/LemonUIbyLemon/LemonUI/issues)! diff --git a/docs/docfx.json b/docs/docfx.json new file mode 100644 index 00000000..abc35ef7 --- /dev/null +++ b/docs/docfx.json @@ -0,0 +1,46 @@ +{ + "metadata": [ + { + "src": [ + { + "files": [ + "bin/Release/**/LemonUI.*.dll" + ], + "src": "../" + } + ], + "dest": "api" + } + ], + "build": { + "content": [ + { + "files": [ + "**/**.{md,yml}" + ], + "exclude": [ + "_site/**", + "obj/**" + ] + }, + { + "files": [ + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "dest": "_site", + "template": [ + "default" + ], + "postProcessors": [] + } +} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..759a689b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,5 @@ +# Welcome to the **LemonUI Documentation**! + +Right now we only have the API Documentation on the top. + +Need something specific? [Feel free to open a GitHub Issue](https://github.com/LemonUIbyLemon/LemonUI/issues)! diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 00000000..fffb0146 --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,3 @@ +- name: API + href: api/ + homepage: api/index.md diff --git a/root.props b/root.props deleted file mode 100644 index 0ed5e0f4..00000000 --- a/root.props +++ /dev/null @@ -1,43 +0,0 @@ - - - false - true - true - - - - 1.5.1 - - - - $(SolutionDir)\bin\$(Configuration)\$(ForFramework) - $(SolutionDir)\bin\$(Configuration)\FOR DEVELOPERS - $(SolutionDir)\bin\$(Configuration)\$(ForFramework)\$(AssemblyName).xml - - - - $(AssemblyName) - true - true - README.md - MIT - logo.png - en-US - - - - Hannele "Lemon" Ruiz - Hannele "Lemon" Ruiz - LemonUI - UI system for Grand Theft Auto V. - https://github.com/justalemon/LemonUI - https://github.com/justalemon/LemonUI.git - git - - - - - - - - \ No newline at end of file diff --git a/stylecop.json b/stylecop.json index 39f180a1..15244466 100644 --- a/stylecop.json +++ b/stylecop.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "settings": { "orderingRules": { "usingDirectivesPlacement": "outsideNamespace"