From 3e48745587d5ac457b04aee32cb20f23e830fa40 Mon Sep 17 00:00:00 2001 From: Grinch_ Date: Thu, 30 Jun 2022 05:56:53 +0600 Subject: [PATCH] Refactor, add favourites --- resource/CheatMenuSA/data/clothes.toml | 23 ++ resource/common/locale/English.toml | 11 +- src/animation.cpp | 19 +- src/cheatmenu.cpp | 29 +- src/datastore.h | 19 ++ src/defines.h | 1 + src/game.cpp | 47 +-- src/menu.cpp | 13 +- src/pch.h | 5 + src/ped.cpp | 47 +-- src/ped.h | 2 +- src/player.cpp | 69 ++--- src/player.h | 2 +- src/resourcestore.cpp | 32 +- src/resourcestore.h | 5 +- src/teleport.cpp | 13 +- src/ui.cpp | 398 ++----------------------- src/ui.h | 55 ---- src/vehicle.cpp | 58 ++-- src/vehicle.h | 4 +- src/visual.cpp | 9 +- src/weapon.cpp | 31 +- src/weapon.h | 7 +- src/widget.cpp | 378 +++++++++++++++++++++++ src/widget.h | 35 +++ 25 files changed, 709 insertions(+), 603 deletions(-) create mode 100644 resource/CheatMenuSA/data/clothes.toml create mode 100644 src/widget.cpp create mode 100644 src/widget.h diff --git a/resource/CheatMenuSA/data/clothes.toml b/resource/CheatMenuSA/data/clothes.toml new file mode 100644 index 0000000..6775722 --- /dev/null +++ b/resource/CheatMenuSA/data/clothes.toml @@ -0,0 +1,23 @@ +############################################################################## +# Cloth Body Part IDs +# Example: "Name" = "ID +############################################################################## + +"Shirts" = "0" +"Heads" = "1" +"Trousers" = "2" +"Shoes" = "3" +"Tattoos left lower arm" = "4" +"Tattoos left upper arm" = "5" +"Tattoos right upper arm" = "6" +"Tattoos right lower arm" = "7" +"Tattoos back" = "8" +"Tattoos left chest" = "9" +"Tattoos right chest" = "10" +"Tattoos stomach" = "11" +"Tattoos lower back" = "12" +"Necklaces" = "13" +"Watches" = "14" +"Glasses" = "15" +"Hats" = "16" +"Extras" = "17" diff --git a/resource/common/locale/English.toml b/resource/common/locale/English.toml index 8d89003..07e4fcf 100644 --- a/resource/common/locale/English.toml +++ b/resource/common/locale/English.toml @@ -182,6 +182,12 @@ OpenCMDUsing = "Open or close command window using %s" OpenMenuKey = "Open/ close cheat menu" Overlay = "Overlay" Position = "Position" +Remove = "Remove" +Favourites = "Add to favourites" +FavouritesText = "Added to favourites" +FavouritesRemove = "Remove from favourites" +FavouritesRemoveText = "Removed from favourites" +Close = "Close" QuickSSKey = "Quick screenshot" QuickTPKey = "Toogle quick teleport" QuickVehSpawnerCMD = "Quick vehicle spawner" @@ -250,7 +256,8 @@ EveryoneAtk = "Everyone attacks players" ExGangWarsTip = "You'll need ExGangWars plugin to display some turf colors" GangsControl = "Gangs control streets" GangsEverywhere = "Gangs everywhere" -GangWars = "Gangs" +Gangs = "Gangs" +GangWars = "Gang wars" Health = "Health" MaxLimit = "Max limit reached" NastyLimbs = "Nasty limbs" @@ -756,6 +763,8 @@ Minimum = "Min" PedPage = "Ped" PlayerPage = "Player" Search = "Search" +LocationsTab = "Locations" +FavouritesTab = "Favourites" SetValue = "Set value" SpawnTab = "Spawn" TeleportPage = "Teleport" diff --git a/src/animation.cpp b/src/animation.cpp index d5465e3..3cd0de1 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "animation.h" #include "ui.h" +#include "widget.h" #include "util.h" #ifdef GTA3 @@ -295,7 +296,7 @@ void Animation::ShowPage() if (ImGui::BeginTabItem(TEXT("Animation.AnimationTab"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Animation.StopAnimation"), Ui::GetSize())) + if (ImGui::Button(TEXT("Animation.StopAnimation"), Widget::CalcSize())) { if (hPlayer) { @@ -332,7 +333,7 @@ void Animation::ShowPage() ImGui::InputTextWithHint(TEXT("Animation.IFPName"), "ped", ifpBuf, INPUT_BUFFER_SIZE); ImGui::InputTextWithHint(TEXT("Animation.AnimName"), "cower", animBuf, INPUT_BUFFER_SIZE); ImGui::Spacing(); - if (ImGui::Button(TEXT("Animation.AddAnimation"), Ui::GetSize())) + if (ImGui::Button(TEXT("Animation.AddAnimation"), Widget::CalcSize())) { std::string key = std::string("Custom.") + animBuf; m_AnimData.m_pData->Set(key.c_str(), std::string(ifpBuf)); @@ -344,7 +345,7 @@ void Animation::ShowPage() if (ImGui::BeginChild("Anims Child")) { ImGui::Spacing(); - Ui::DrawList(m_AnimData, Play, Remove); + Widget::DataList(m_AnimData, Play, Remove); ImGui::EndChild(); } } @@ -354,7 +355,7 @@ void Animation::ShowPage() if (ImGui::BeginTabItem(TEXT("Animation.CutsceneTab"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Animation.StopCutscene"), Ui::GetSize())) + if (ImGui::Button(TEXT("Animation.StopCutscene"), Widget::CalcSize())) { if (Cutscene::m_bRunning) { @@ -373,7 +374,7 @@ void Animation::ShowPage() if (ImGui::BeginChild("Cutscene Child")) { ImGui::Spacing(); - Ui::DrawList(Cutscene::m_Data, Cutscene::Play, nullptr); + Widget::DataList(Cutscene::m_Data, Cutscene::Play, nullptr); ImGui::EndChild(); } ImGui::EndTabItem(); @@ -381,7 +382,7 @@ void Animation::ShowPage() if (ImGui::BeginTabItem(TEXT("Animation.ParticleTab"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Animation.RemoveAll"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Animation.RemoveAll"), Widget::CalcSize(2))) { for (int& p : Particle::m_nParticleList) { @@ -390,7 +391,7 @@ void Animation::ShowPage() Particle::m_nParticleList.clear(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Animation.RemoveLatest"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Animation.RemoveLatest"), Widget::CalcSize(2))) { Command(Particle::m_nParticleList.back()); // stop if anything is running Particle::m_nParticleList.pop_back(); @@ -406,7 +407,7 @@ void Animation::ShowPage() static char buf[INPUT_BUFFER_SIZE]; ImGui::InputTextWithHint(TEXT("Animation.ParticleName"), "kkjj_on_fire", buf, INPUT_BUFFER_SIZE); ImGui::Spacing(); - if (ImGui::Button(TEXT("Animation.AddParticle"), Ui::GetSize())) + if (ImGui::Button(TEXT("Animation.AddParticle"), Widget::CalcSize())) { std::string key = std::string("Custom.") + buf; m_AnimData.m_pData->Set(key.c_str(), std::string("Dummy")); @@ -417,7 +418,7 @@ void Animation::ShowPage() if (ImGui::BeginChild("Anims Child")) { ImGui::Spacing(); - Ui::DrawList(Particle::m_Data, Particle::Play, Particle::Remove); + Widget::DataList(Particle::m_Data, Particle::Play, Particle::Remove); ImGui::EndChild(); } ImGui::EndTabItem(); diff --git a/src/cheatmenu.cpp b/src/cheatmenu.cpp index c0d7ddd..db34984 100644 --- a/src/cheatmenu.cpp +++ b/src/cheatmenu.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "ui.h" +#include "widget.h" #include "updater.h" #include "d3dhook.h" #include "../depend/imgui/imgui_internal.h" @@ -74,7 +75,7 @@ void CheatMenu::DrawWindow() void CheatMenu::ProcessPages() { static void* pCallback; - ImVec2 size = Ui::GetSize(3, false); + ImVec2 size = Widget::CalcSize(3, false); ImGuiStyle &style = ImGui::GetStyle(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); @@ -263,7 +264,7 @@ void CheatMenu::Init() void CheatMenu::ShowAnniversaryPage() { - Ui::CenterdText("Happy Anniversary!"); + Widget::TextCentered("Happy Anniversary!"); ImGui::NewLine(); ImGui::TextWrapped("On this day, in 2019, the first public version of menu was released in MixMods Forum." @@ -274,12 +275,12 @@ void CheatMenu::ShowAnniversaryPage() ImGui::TextWrapped("Feel free to star the GitHub repo or join the discord server and provide feedback, ideas, or suggestions."); ImGui::NewLine(); - if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Widget::CalcSize(3)))) { ShellExecute(nullptr, "open", DISCORD_INVITE, nullptr, nullptr, SW_SHOWNORMAL); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Widget::CalcSize(3)))) { ShellExecute(nullptr, "open", GITHUB_LINK, nullptr, nullptr, SW_SHOWNORMAL); } @@ -289,48 +290,48 @@ void CheatMenu::ShowWelcomePage() { ImGui::NewLine(); - Ui::CenterdText(TEXT("Menu.WelcomeMSG")); - Ui::CenterdText(std::format("{}: Grinch_",TEXT("Menu.Author"))); + Widget::TextCentered(TEXT("Menu.WelcomeMSG")); + Widget::TextCentered(std::format("{}: Grinch_",TEXT("Menu.Author"))); ImGui::NewLine(); ImGui::TextWrapped(TEXT("Menu.EnsureLatest")); ImGui::NewLine(); - if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Widget::CalcSize(2)))) { ShellExecute(nullptr, "open", DISCORD_INVITE, nullptr, nullptr, SW_SHOWNORMAL); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Widget::CalcSize(2)))) { ShellExecute(nullptr, "open", GITHUB_LINK, nullptr, nullptr, SW_SHOWNORMAL); } ImGui::NewLine(); ImGui::TextWrapped(TEXT("Menu.BugDisclaimer")); ImGui::Dummy(ImVec2(0, 30)); - Ui::CenterdText(TEXT("Menu.CopyrightDisclaimer")); + Widget::TextCentered(TEXT("Menu.CopyrightDisclaimer")); } void CheatMenu::ShowUpdatePage() { std::string ver = Updater::GetUpdateVersion(); ImGui::Dummy(ImVec2(0, 20)); - Ui::CenterdText(TEXT("Menu.NewVersion")); - Ui::CenterdText(std::format("{}: {}", TEXT("Menu.CurrentVersion"), MENU_VERSION)); - Ui::CenterdText(TEXT("Menu.LatestVersion") + ver); + Widget::TextCentered(TEXT("Menu.NewVersion")); + Widget::TextCentered(std::format("{}: {}", TEXT("Menu.CurrentVersion"), MENU_VERSION)); + Widget::TextCentered(TEXT("Menu.LatestVersion") + ver); ImGui::Dummy(ImVec2(0, 10)); ImGui::TextWrapped(TEXT("Menu.UpdaterInfo1")); ImGui::Dummy(ImVec2(0, 10)); ImGui::TextWrapped(TEXT("Menu.UpdaterInfo2")); ImGui::Dummy(ImVec2(0, 5)); - if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Widget::CalcSize(2)))) { ShellExecute(nullptr, "open", DISCORD_INVITE, nullptr, nullptr, SW_SHOWNORMAL); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Menu.DownloadPage"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Menu.DownloadPage"), Widget::CalcSize(2))) { ShellExecute(NULL, "open", std::string("https://github.com/user-grinch/Cheat-Menu/releases/tag/" + ver).c_str(), NULL, NULL, SW_SHOWNORMAL); diff --git a/src/datastore.h b/src/datastore.h index 39603a9..2da9b11 100644 --- a/src/datastore.h +++ b/src/datastore.h @@ -40,6 +40,25 @@ public: } return defaultVal; } + + Table* GetTable(const char* key) noexcept + { + if (pTable) + { + Table *tbl = (*pTable).at_path(key).as_table(); + if (tbl) + { + return tbl; + } + else + { + pTable->insert(key, Table()); + return (*pTable).at_path(key).as_table(); + + } + } + return nullptr; + } // Adds data to the structure diff --git a/src/defines.h b/src/defines.h index 756390c..aa4a1fa 100644 --- a/src/defines.h +++ b/src/defines.h @@ -23,3 +23,4 @@ #define FILE_NAME BY_GAME("CheatMenuSA" , "CheatMenuVC", "CheatMenuIII") + diff --git a/src/game.cpp b/src/game.cpp index e97b2b1..4109639 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2,6 +2,7 @@ #include "menu.h" #include "game.h" #include "ui.h" +#include "widget.h" #include "util.h" #ifdef GTASA #include @@ -410,7 +411,7 @@ void Game::ShowPage() int hplayer = CPools::GetPedRef(pPlayer); #ifdef GTASA - if (ImGui::Button(TEXT("Game.SaveGame"), Ui::GetSize())) + if (ImGui::Button(TEXT("Game.SaveGame"), Widget::CalcSize())) { FrontEndMenuManager.m_bActivateMenuNextFrame = true; bSaveGameFlag = true; @@ -652,36 +653,36 @@ void Game::ShowPage() if (ImGui::CollapsingHeader(TEXT("Game.Weather"))) { #ifdef GTASA - if (ImGui::Button(TEXT("Game.Foggy"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Foggy"), Widget::CalcSize(3))) { Call<0x438F80>(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Overcast"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Overcast"), Widget::CalcSize(3))) { Call<0x438F60>(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Rainy"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Rainy"), Widget::CalcSize(3))) { Call<0x438F70>(); } - if (ImGui::Button(TEXT("Game.Sandstorm"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Sandstorm"), Widget::CalcSize(3))) { Call<0x439590>(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Thunderstorm"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Thunderstorm"), Widget::CalcSize(3))) { Call<0x439570>(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.VerySunny"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.VerySunny"), Widget::CalcSize(3))) { Call<0x438F50>(); } @@ -702,40 +703,40 @@ void Game::ShowPage() CWeather::OldWeatherType = weatherID; CWeather::NewWeatherType = weatherID; } - Ui::ShowTooltip(TEXT("Game.WeatherIDText")); + Widget::Tooltip(TEXT("Game.WeatherIDText")); #else - if (ImGui::Button(TEXT("Game.Sunny"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Sunny"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(0); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Cloudy"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Cloudy"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(1); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Rainy"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Rainy"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(2); } - if (ImGui::Button(TEXT("Game.Foggy"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Foggy"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(3); } #ifdef GTAVC ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.ExtraSunny"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.ExtraSunny"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(4); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.Hurricane"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.Hurricane"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(5); } - if (ImGui::Button(TEXT("Game.ExtraColors"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Game.ExtraColors"), Widget::CalcSize(3))) { CWeather::ForceWeatherNow(6); } @@ -755,14 +756,14 @@ void Game::ShowPage() { ImGui::TextWrapped(TEXT("Game.MissionLoaderTip")); ImGui::Spacing(); - if (ImGui::Button(TEXT("Game.ShowLoader"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Game.ShowLoader"), ImVec2(Widget::CalcSize()))) { bMissionLoaderWarningShown = true; } } else { - if (ImGui::Button(TEXT("Game.FailMission"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Game.FailMission"), ImVec2(Widget::CalcSize()))) { if (!Util::IsOnCutscene()) { @@ -772,17 +773,17 @@ void Game::ShowPage() ImGui::Spacing(); - Ui::DrawList(m_MissionData, SetPlayerMission, nullptr); + Widget::DataList(m_MissionData, SetPlayerMission, nullptr); } ImGui::EndTabItem(); } #ifdef GTASA if (ImGui::BeginTabItem(TEXT("Game.Stats"))) { - // similar to Ui::DrawList() + // similar to Widget::DataList() ImGui::Spacing(); - if (ImGui::Button(TEXT("Game.MaxWepSkills"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Game.MaxWepSkills"), Widget::CalcSize(2))) { for (size_t i = 69; i != 80; ++i) { @@ -792,7 +793,7 @@ void Game::ShowPage() SetHelpMessage(TEXT("Game.MaxWepSkillsText")); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Game.MaxVehSkills"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Game.MaxVehSkills"), Widget::CalcSize(2))) { CStats::SetStatValue(160, 1000); CStats::SetStatValue(223, 1000); @@ -806,7 +807,7 @@ void Game::ShowPage() ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - ImGui::GetStyle().ItemSpacing.x)/2); Ui::ListBoxStr("##Categories", m_StatData.m_Categories, m_StatData.m_Selected); ImGui::SameLine(); - Ui::FilterWithHint("##Filter", m_StatData.m_Filter, TEXT("Window.Search")); + Widget::FilterWithHint("##Filter", m_StatData.m_Filter, TEXT("Window.Search")); ImGui::PopItemWidth(); ImGui::Spacing(); @@ -841,7 +842,7 @@ void Game::ShowPage() ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth() / 2); ImGui::SliderInt(TEXT("Game.ActivateTimer"), &RandomCheats::m_nInterval, 5, 60); - Ui::ShowTooltip(TEXT("Game.ActivateTimerText")); + Widget::Tooltip(TEXT("Game.ActivateTimerText")); ImGui::PopItemWidth(); diff --git a/src/menu.cpp b/src/menu.cpp index fa9358d..eadbc61 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "menu.h" #include "ui.h" +#include "widget.h" #include "util.h" #include "updater.h" #include "cheatmenu.h" @@ -324,7 +325,7 @@ void Menu::ShowPage() if (ImGui::BeginTabItem(TEXT("Menu.Config"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Menu.ResetSize"), ImVec2(Ui::GetSize(1)))) + if (ImGui::Button(TEXT("Menu.ResetSize"), ImVec2(Widget::CalcSize(1)))) { CheatMenu::ResetMenuSize(); } @@ -448,7 +449,7 @@ void Menu::ShowPage() { ImGui::Spacing(); ImGui::Text(TEXT("Menu.Usage")); - Ui::ShowTooltip(TEXT("Menu.UsageText")); + Widget::Tooltip(TEXT("Menu.UsageText")); ImGui::Spacing(); ImGui::BeginChild("Hotkeys"); menuOpen.DrawUI(TEXT("Menu.OpenMenuKey")); @@ -530,21 +531,21 @@ void Menu::ShowPage() { ImGui::Spacing(); - if (ImGui::Button(TEXT("Menu.CheckUpdate"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Menu.CheckUpdate"), ImVec2(Widget::CalcSize(3)))) { Updater::CheckUpdate(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Menu.DiscordServer"), ImVec2(Widget::CalcSize(3)))) { ShellExecute(nullptr, "open", DISCORD_INVITE, nullptr, nullptr, SW_SHOWNORMAL); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Menu.GitHubRepo"), ImVec2(Widget::CalcSize(3)))) { ShellExecute(nullptr, "open", GITHUB_LINK, nullptr, nullptr, SW_SHOWNORMAL); } @@ -566,7 +567,7 @@ void Menu::ShowPage() ImGui::Dummy(ImVec2(0, 10)); ImGui::TextWrapped(TEXT("Menu.BugDisclaimer")); ImGui::Dummy(ImVec2(0, 10)); - Ui::CenterdText(TEXT("Menu.CopyrightDisclaimer")); + Widget::TextCentered(TEXT("Menu.CopyrightDisclaimer")); ImGui::Dummy(ImVec2(0, 30)); if (ImGui::BeginTable("Hall of Fame", 2, ImGuiTableFlags_ScrollY)) diff --git a/src/pch.h b/src/pch.h index f4ab259..b4448ab 100644 --- a/src/pch.h +++ b/src/pch.h @@ -77,6 +77,11 @@ enum eRenderer extern eRenderer gRenderer; extern DataStore gConfig; +typedef void(*ArgCallback3)(std::string&, std::string&, std::string&); +typedef void(*ArgCallback)(std::string&); +typedef std::string(*ArgCallbackRtn)(std::string&); +typedef bool(*ArgCallbackRtnBool)(std::string&); + // Fix function clashes static void SetHelpMessage(const char *message, bool b1 = false, bool b2 = false, bool b3 = false) { diff --git a/src/ped.cpp b/src/ped.cpp index 36750d3..5a80a2d 100644 --- a/src/ped.cpp +++ b/src/ped.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "ped.h" #include "ui.h" +#include "widget.h" #include "util.h" #include "weapon.h" #include @@ -266,7 +267,7 @@ void Ped::ShowPage() static int removeRadius = 5; ImGui::InputInt(TEXT("Ped.Radius"), &removeRadius); ImGui::Spacing(); - if (ImGui::Button(TEXT("Ped.RemovePeds"), Ui::GetSize(1))) + if (ImGui::Button(TEXT("Ped.RemovePeds"), Widget::CalcSize(1))) { CPlayerPed* player = FindPlayerPed(); for (CPed* ped : CPools::ms_pPedPool) @@ -287,7 +288,7 @@ void Ped::ShowPage() if (ImGui::BeginTabItem(TEXT("Window.SpawnTab"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Ped.RemoveFrozen"), Ui::GetSize(1))) + if (ImGui::Button(TEXT("Ped.RemoveFrozen"), Widget::CalcSize(1))) { for (CPed* ped : Spawner::m_List) { @@ -301,17 +302,17 @@ void Ped::ShowPage() { ImGui::Spacing(); - if (ImGui::BeginTabItem(TEXT("Ped.SpawnerTab"))) + if (ImGui::BeginTabItem(TEXT("Window.Search"))) { ImGui::Spacing(); #ifdef GTASA - Ui::DrawImages(m_PedData, SpawnPed, nullptr, - [](std::string str) + Widget::ImageList(m_PedData, SpawnPed, nullptr, + [](std::string& str) { return m_PedData.m_pData->Get(str.c_str(), "Unknown"); }); #else - Ui::DrawList(m_PedData, SpawnPed, nullptr); + Widget::DataList(m_PedData, SpawnPed, nullptr); #endif ImGui::EndTabItem(); } @@ -340,30 +341,33 @@ void Ped::ShowPage() } } ImGui::Combo(TEXT("Ped.PedType"), &Spawner::m_nSelectedPedType, pedTypeList); - + ImGui::EndChild(); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem(TEXT("Window.WeaponPage"))) + { static std::string weaponName = "None"; ImGui::Spacing(); ImGui::Text(TEXT("Ped.SelectedWeapon"), weaponName.c_str()); ImGui::Spacing(); #ifdef GTASA - Ui::DrawImages(Weapon::m_WeaponData, - [](std::string str) + Widget::ImageList(Weapon::m_WeaponData, + [](std::string& str) { Spawner::m_nWeaponId = std::stoi(str); + weaponName = Weapon::m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); }, nullptr, - [](std::string str) + [](std::string& str) { - weaponName = Weapon::m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); - return weaponName; + return Weapon::m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); }, - [](std::string str) + [](std::string& str) { return str != "-1"; /*Jetpack*/ - } - ); + }); #else - Ui::DrawList(Weapon::m_WeaponData, + Widget::DataList(Weapon::m_WeaponData, [](std::string& root, std::string& key, std::string& id) { SpawnPed::m_nWeaponId = std::stoi(id); @@ -371,19 +375,18 @@ void Ped::ShowPage() }, nullptr); #endif - ImGui::Spacing(); - ImGui::EndChild(); ImGui::EndTabItem(); } ImGui::EndTabBar(); } ImGui::EndTabItem(); } + #ifdef GTASA - if (ImGui::BeginTabItem(TEXT("Ped.GangWars"))) + if (ImGui::BeginTabItem(TEXT("Ped.Gangs"))) { ImGui::Spacing(); - if (ImGui::Button(TEXT("Ped.StartWar"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Ped.StartWar"), ImVec2(Widget::CalcSize(2)))) { if (Util::GetLargestGangInZone() == 1) { @@ -396,7 +399,7 @@ void Ped::ShowPage() CGangWars::bGangWarsActive = true; } ImGui::SameLine(); - if (ImGui::Button(TEXT("Ped.EndWar"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Ped.EndWar"), ImVec2(Widget::CalcSize(2)))) { CGangWars::EndGangWar(true); } @@ -430,7 +433,7 @@ void Ped::ShowPage() ImGui::Spacing(); ImGui::TextWrapped(TEXT("Ped.ExGangWarsTip")); ImGui::Spacing(); - if (ImGui::Button(TEXT("Ped.DownloadExGangWars"), Ui::GetSize(1))) + if (ImGui::Button(TEXT("Ped.DownloadExGangWars"), Widget::CalcSize(1))) { ShellExecute(NULL, "open", "https://gtaforums.com/topic/682194-extended-gang-wars/", NULL, NULL, SW_SHOWNORMAL); diff --git a/src/ped.h b/src/ped.h index db56218..0f3b02e 100644 --- a/src/ped.h +++ b/src/ped.h @@ -27,7 +27,7 @@ private: public: #ifdef GTASA static inline DataStore m_SpecialPedData {"special_peds"}; - static inline ResourceStore m_PedData{"peds", eResourceType::TYPE_BOTH, ImVec2(65, 110)}; + static inline ResourceStore m_PedData{"peds", eResourceType::TYPE_IMAGE_TEXT, ImVec2(65, 110)}; #else static inline ResourceStore m_PedData {"peds", eResourceType::TYPE_TEXT}; #endif diff --git a/src/player.cpp b/src/player.cpp index 80b0ce8..d6118f2 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2,6 +2,7 @@ #include "player.h" #include "menu.h" #include "ui.h" +#include "widget.h" #include "util.h" #ifdef GTASA @@ -268,39 +269,34 @@ void Player::Init() #ifdef GTASA void Player::ChangePlayerCloth(std::string& name) { - std::stringstream ss(name); - std::string temp; + int bodyPart; + char model[16], tex[16]; - getline(ss, temp, '$'); - int body_part = std::stoi(temp); - - getline(ss, temp, '$'); - std::string model = temp.c_str(); - - getline(ss, temp, '$'); - std::string texName = temp.c_str(); + if (sscanf(name.c_str(), "%d$%[^$]$%s", &bodyPart, &model, &tex) != 3) + { + return; + } CPlayerPed* player = FindPlayerPed(); - - if (texName == "cutoffchinosblue") + if (!strcmp(tex, "cutoffchinosblue")) { - player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-697413025, 744365350, body_part); + player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-697413025, 744365350, bodyPart); } else { - if (texName == "sneakerbincblue") + if (!strcmp(tex, "sneakerbincblue")) { - player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-915574819, 2099005073, body_part); + player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-915574819, 2099005073, bodyPart); } else { - if (texName == "12myfac") + if (!strcmp(tex, "12myfac")) { - player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-1750049245, 1393983095, body_part); + player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(-1750049245, 1393983095, bodyPart); } else { - player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(texName.c_str(), model.c_str(), body_part); + player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(tex, model, bodyPart); } } } @@ -388,7 +384,7 @@ void Player::ShowPage() #endif CPlayerInfo *pInfo = &CWorld::Players[CWorld::PlayerInFocus]; - if (ImGui::Button(TEXT("Player.CopyCoordinates"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Player.CopyCoordinates"), ImVec2(Widget::CalcSize(2)))) { CVector pos = pPlayer->GetPosition(); std::string text = std::to_string(pos.x) + ", " + std::to_string(pos.y) + ", " + std::to_string(pos.z); @@ -397,7 +393,7 @@ void Player::ShowPage() SetHelpMessage(TEXT("Player.CoordCopied")); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Player.Suicide"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Player.Suicide"), ImVec2(Widget::CalcSize(2)))) { pPlayer->m_fHealth = 0.0; } @@ -647,7 +643,7 @@ void Player::ShowPage() ImGui::TextWrapped(TEXT("Player.NeedCJSkin")); ImGui::Spacing(); - if (ImGui::Button(TEXT("Player.ChangeToCJ"), ImVec2(Ui::GetSize(1)))) + if (ImGui::Button(TEXT("Player.ChangeToCJ"), ImVec2(Widget::CalcSize(1)))) { pPlayer->SetModelIndex(0); Util::ClearCharTasksVehCheck(pPlayer); @@ -724,7 +720,7 @@ void Player::ShowPage() } ImGui::Spacing(); - if (ImGui::Button(TEXT("Window.Minimum"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Window.Minimum"), Widget::CalcSize(3))) { #ifdef GTASA pPlayer->CheatWantedLevel(0); @@ -737,7 +733,7 @@ void Player::ShowPage() ImGui::SameLine(); - if (ImGui::Button(TEXT("Window.Default"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Window.Default"), Widget::CalcSize(3))) { #ifdef GTASA pPlayer->CheatWantedLevel(0); @@ -750,7 +746,7 @@ void Player::ShowPage() ImGui::SameLine(); - if (ImGui::Button(TEXT("Window.Maximum"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Window.Maximum"), Widget::CalcSize(3))) { #ifdef GTASA pPlayer->CheatWantedLevel(max_wl); @@ -783,7 +779,7 @@ void Player::ShowPage() { if (pPlayer->m_nModelIndex == 0) { - Ui::DrawImages(m_ClothData, ChangePlayerCloth, nullptr, [](std::string str) + Widget::ImageList(m_ClothData, ChangePlayerCloth, nullptr, [](std::string& str) { std::stringstream ss(str); std::string temp; @@ -792,14 +788,14 @@ void Player::ShowPage() getline(ss, temp, '$'); return temp; - }, nullptr, clothNameList, sizeof(clothNameList) / sizeof(const char*)); + });// nullptr, clothNameList, sizeof(clothNameList) / sizeof(const char*)); } else { ImGui::TextWrapped(TEXT("Player.NeedCJSkin")); ImGui::Spacing(); - if (ImGui::Button(TEXT("Player.ChangeToCJ"), ImVec2(Ui::GetSize(1)))) + if (ImGui::Button(TEXT("Player.ChangeToCJ"), ImVec2(Widget::CalcSize(1)))) { pPlayer->SetModelIndex(0); Util::ClearCharTasksVehCheck(pPlayer); @@ -815,7 +811,7 @@ void Player::ShowPage() ImGui::BeginChild("ClothesRemove"); size_t count = 0; - if (ImGui::Button(TEXT("Player.RemoveAll"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Player.RemoveAll"), ImVec2(Widget::CalcSize(2)))) { CPlayerPed* player = FindPlayerPed(); for (uint i = 0; i < 18; i++) @@ -825,9 +821,9 @@ void Player::ShowPage() CClothes::RebuildPlayer(player, false); } ImGui::SameLine(); - for (const char* clothName : clothNameList) + for (auto [k, v] : m_ClothData.m_pData->Items()) { - if (ImGui::Button(clothName, ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(std::string(k.str()).c_str(), ImVec2(Widget::CalcSize(2)))) { CPlayerPed* player = FindPlayerPed(); player->m_pPlayerData->m_pPedClothesDesc->SetTextureAndModel(0u, 0u, count); @@ -840,13 +836,14 @@ void Player::ShowPage() } ++count; } + ImGui::EndChild(); ImGui::EndTabItem(); } if (ImGui::BeginTabItem(TEXT("Player.PedSkinsTab"))) { - Ui::DrawImages(Ped::m_PedData, ChangePlayerModel, nullptr, - [](std::string str) + Widget::ImageList(Ped::m_PedData, ChangePlayerModel, nullptr, + [](std::string& str) { return Ped::m_PedData.m_pData->Get(str.c_str(), "Unknown"); }); @@ -858,10 +855,10 @@ void Player::ShowPage() if (m_bModloaderInstalled) { - Ui::FilterWithHint(TEXT("Window.Search"), m_ClothData.m_Filter, + Widget::FilterWithHint(TEXT("Window.Search"), m_ClothData.m_Filter, std::string(TEXT("Player.TotalSkins") + std::to_string(CustomSkins::m_List.size())) .c_str()); - Ui::ShowTooltip(TEXT("Player.CustomSkinsDirTip")); + Widget::Tooltip(TEXT("Player.CustomSkinsDirTip")); ImGui::Spacing(); ImGui::TextWrapped(TEXT("Player.CustomSkinsTip")); ImGui::Spacing(); @@ -880,7 +877,7 @@ void Player::ShowPage() { ImGui::TextWrapped(TEXT("Player.CustomSkinTutorial")); ImGui::Spacing(); - if (ImGui::Button(TEXT("Player.DownloadModloader"), ImVec2(Ui::GetSize(1)))) + if (ImGui::Button(TEXT("Player.DownloadModloader"), ImVec2(Widget::CalcSize(1)))) ShellExecute(NULL, "open", "https://gtaforums.com/topic/669520-mod-loader/", NULL, NULL, SW_SHOWNORMAL); } @@ -900,7 +897,7 @@ void Player::ShowPage() #else ImGui::TextWrapped(TEXT("Player.WorkSkinOnly")); #endif - Ui::DrawList(skinData, ChangePlayerModel, nullptr); + Widget::DataList(skinData, ChangePlayerModel, nullptr); ImGui::EndTabItem(); } #endif diff --git a/src/player.h b/src/player.h index 884119a..99e3491 100644 --- a/src/player.h +++ b/src/player.h @@ -18,7 +18,7 @@ private: static inline bool m_bAimSkinChanger; static inline bool m_bDrunkEffect; static inline bool m_bFastSprint; - static inline ResourceStore m_ClothData { "clothes", eResourceType::TYPE_IMAGE, ImVec2(70, 100)}; + static inline ResourceStore m_ClothData { "clothes", eResourceType::TYPE_TEXT_IMAGE, ImVec2(70, 100)}; struct CustomSkins { static inline ImGuiTextFilter m_Filter; diff --git a/src/resourcestore.cpp b/src/resourcestore.cpp index 283293d..2c23bfd 100644 --- a/src/resourcestore.cpp +++ b/src/resourcestore.cpp @@ -2,13 +2,13 @@ #include "pch.h" ResourceStore::ResourceStore(const char* text, eResourceType type, ImVec2 imageSize) - : m_ImageSize(imageSize) + : m_ImageSize(imageSize), m_Type(type) { - if (type == eResourceType::TYPE_TEXT || type == eResourceType::TYPE_BOTH) + if (m_Type != eResourceType::TYPE_IMAGE) { m_pData = std::make_unique(text); - if (type == eResourceType::TYPE_TEXT) + if (m_Type != eResourceType::TYPE_IMAGE_TEXT) { // Generate categories for (auto [k, v] : m_pData->Items()) @@ -18,7 +18,7 @@ ResourceStore::ResourceStore(const char* text, eResourceType type, ImVec2 imageS } } - if (type == eResourceType::TYPE_IMAGE || type == eResourceType::TYPE_BOTH) + if (m_Type != eResourceType::TYPE_TEXT) { /* Textures need to be loaded from main thread @@ -66,6 +66,7 @@ void ResourceStore::LoadTextureResource(std::string&& name) { RwLinkList *pRLL = (RwLinkList*)pRwTexDictionary->texturesInDict.link.next; RwTexDictionary *pEndDic; + bool addCategories = m_Categories.empty(); do { pEndDic = (RwTexDictionary*)pRLL->link.next; @@ -82,7 +83,24 @@ void ResourceStore::LoadTextureResource(std::string&& name) std::string str; getline(ss, str, '$'); - m_ImagesList.back().get()->m_CategoryName = str; + + if (m_Type == TYPE_TEXT_IMAGE) + { + // generate categories from text data + for (auto [k, v] : m_pData->Items()) + { + std::string val = v.value_or("Unknown"); + if (val == str) + { + m_ImagesList.back().get()->m_CategoryName = k.str(); + break; + } + } + } + else + { + m_ImagesList.back().get()->m_CategoryName = str; + } if (name == "clothes") { @@ -96,10 +114,12 @@ void ResourceStore::LoadTextureResource(std::string&& name) } // Genereate categories - if (!std::count(m_Categories.begin(), m_Categories.end(), m_ImagesList.back().get()->m_CategoryName)) + if (m_Type == TYPE_IMAGE_TEXT && + !std::count(m_Categories.begin(), m_Categories.end(), m_ImagesList.back().get()->m_CategoryName)) { m_Categories.push_back(m_ImagesList.back().get()->m_CategoryName); } + pRLL = (RwLinkList*)pEndDic; } while ( pEndDic != (RwTexDictionary*)&pRwTexDictionary->texturesInDict ); diff --git a/src/resourcestore.h b/src/resourcestore.h index 30df05e..1ca82c0 100644 --- a/src/resourcestore.h +++ b/src/resourcestore.h @@ -1,3 +1,4 @@ +#pragma once #include #include #include "datastore.h" @@ -40,7 +41,8 @@ enum eResourceType { TYPE_IMAGE, TYPE_TEXT, - TYPE_BOTH, + TYPE_IMAGE_TEXT, // priotizes images + TYPE_TEXT_IMAGE, // priotizes texts }; /* @@ -60,6 +62,7 @@ public: std::unique_ptr m_pData; std::vector> m_ImagesList; ImVec2 m_ImageSize; + eResourceType m_Type; bool m_bTexturesLoaded = false; ResourceStore(const char* text, eResourceType type = TYPE_IMAGE, ImVec2 imageSize = ImVec2(64, 64)); diff --git a/src/teleport.cpp b/src/teleport.cpp index 3518942..2ccbae8 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -2,6 +2,7 @@ #include "teleport.h" #include "menu.h" #include "ui.h" +#include "widget.h" #include "util.h" #ifdef GTASA @@ -239,7 +240,7 @@ void Teleport::ShowPage() ImGui::Spacing(); - if (ImGui::Button(TEXT("Teleport.TeleportToCoord"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Teleport.TeleportToCoord"), Widget::CalcSize(2))) { CVector pos{0, 0, 10}; @@ -256,12 +257,12 @@ void Teleport::ShowPage() } ImGui::SameLine(); #ifdef GTASA - if (ImGui::Button(TEXT("Teleport.TeleportMarker"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Teleport.TeleportMarker"), Widget::CalcSize(2))) { TeleportPlayer(true); } #else - if (ImGui::Button(TEXT("Teleport.TeleportCenter"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Teleport.TeleportCenter"), Widget::CalcSize(2))) { TeleportPlayer(false, CVector(0, 0, 23)); } @@ -271,7 +272,7 @@ void Teleport::ShowPage() ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(TEXT("Window.Search"))) + if (ImGui::BeginTabItem(TEXT("Window.LocationsTab"))) { #ifdef GTASA FetchRadarSpriteData(); @@ -283,7 +284,7 @@ void Teleport::ShowPage() ImGui::InputTextWithHint(TEXT("Teleport.Location"), TEXT("Teleport.LocationHint"), m_nLocationBuffer, IM_ARRAYSIZE(m_nInputBuffer)); ImGui::InputTextWithHint(TEXT("Teleport.Coordinates"), "x, y, z", m_nInputBuffer, IM_ARRAYSIZE(m_nInputBuffer)); ImGui::Spacing(); - if (ImGui::Button(TEXT("Teleport.AddLocation"), Ui::GetSize())) + if (ImGui::Button(TEXT("Teleport.AddLocation"), Widget::CalcSize())) { std::string key = std::string("Custom.") + m_nLocationBuffer; m_tpData.m_pData->Set(key.c_str(), ("0, " + std::string(m_nInputBuffer))); @@ -298,7 +299,7 @@ void Teleport::ShowPage() } ImGui::Spacing(); - Ui::DrawList(m_tpData, TeleportToLocation, RemoveTeleportEntry); + Widget::DataList(m_tpData, TeleportToLocation, RemoveTeleportEntry); ImGui::EndTabItem(); } ImGui::EndTabBar(); diff --git a/src/ui.cpp b/src/ui.cpp index 340d727..106993e 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -1,9 +1,38 @@ #include "pch.h" #include "util.h" #include "ui.h" +#include "widget.h" #include "../depend/imgui/imgui_internal.h" #include "menu.h" +ImVec2 Ui::GetSize(short count, bool spacing) +{ + if (count == 1) + { + spacing = false; + } + + // manually tested values + float factor = ImGui::GetStyle().ItemSpacing.x / 2.0f; + float x; + + if (count == 3) + { + factor = ImGui::GetStyle().ItemSpacing.x / 1.403f; + } + + if (spacing) + { + x = ImGui::GetWindowContentRegionWidth() / count - factor; + } + else + { + x = ImGui::GetWindowContentRegionWidth() / count; + } + + return ImVec2(x, ImGui::GetFrameHeight() * 1.3f); +} + // Really messy code, cleanup someday bool Ui::DrawTitleBar() { @@ -12,7 +41,7 @@ bool Ui::DrawTitleBar() ImGuiID id = window->GetID("#CLOSE"); ImGui::PushFont(FontMgr::Get("title")); - CenterdText(MENU_TITLE); + Widget::TextCentered(MENU_TITLE); if (!ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) @@ -49,56 +78,6 @@ bool Ui::DrawTitleBar() return pressed; } -bool Ui::RoundedImageButton(ImTextureID user_texture_id, ImVec2& size, const char* hover_text) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->SkipItems) - return false; - - // Default to using texture ID as ID. User can still push string/integer prefixes. - ImGui::PushID((void*)(intptr_t)user_texture_id); - const ImGuiID id = window->GetID("#image"); - ImGui::PopID(); - - ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); - ImGui::ItemSize(bb); - if (!ImGui::ItemAdd(bb, id)) - return false; - - window->DrawList->AddImageRounded(user_texture_id, bb.Min, bb.Max, ImVec2(0, 0), ImVec2(1, 1), ImGui::GetColorU32(ImVec4(1, 1, 1, 1)), 5.0f); - - if (ImGui::IsItemHovered()) - { - window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_ModalWindowDimBg), 5.6f); - - // Calculating and drawing text over the image - ImVec2 textSize = ImGui::CalcTextSize(hover_text); - if (textSize.x < size.x) - { - float offsetX = (ImGui::GetItemRectSize().x - textSize.x) / 2; - window->DrawList->AddText(ImVec2(bb.Min.x + offsetX, bb.Min.y + 10), ImGui::GetColorU32(ImGuiCol_Text), hover_text); - } - else - { - std::string buf = ""; - std::stringstream ss(hover_text); - short count = 1; - - while (ss >> buf) - { - textSize = ImGui::CalcTextSize(buf.c_str()); - float offsetX = (ImGui::GetItemRectSize().x - textSize.x) / 2; - window->DrawList->AddText(ImVec2(bb.Min.x + offsetX, bb.Min.y + 10 * count), - ImGui::GetColorU32(ImGuiCol_Text), buf.c_str()); - ++count; - } - } - } - - return ImGui::IsItemClicked(0); -} - bool Ui::ListBox(const char* label, const std::vector& all_items, int& selected) { bool rtn = false; @@ -139,84 +118,6 @@ bool Ui::ListBoxStr(const char* label, const std::vector& all_items return rtn; } -bool Ui::ListBoxCustomNames(const char* label, std::string& selected, const char* customNames[], size_t length) -{ - bool rtn = false; - std::string display_selected = (selected == "All") ? selected : customNames[std::stoi(selected)]; - - if (ImGui::BeginCombo(label, display_selected.c_str())) - { - if (ImGui::MenuItem("All")) - { - selected = "All"; - rtn = true; - } - - for (size_t i = 0; i < length; ++i) - { - if (ImGui::MenuItem(customNames[i])) - { - selected = std::to_string(i); - rtn = true; - break; - } - } - ImGui::EndCombo(); - } - return rtn; -} - -ImVec2 Ui::GetSize(short count, bool spacing) -{ - if (count == 1) - { - spacing = false; - } - - float factor = ImGui::GetStyle().ItemSpacing.x / 2.0f; - float x; - - if (count == 3) - { - factor = ImGui::GetStyle().ItemSpacing.x / 1.403f; - } - - if (spacing) - { - x = ImGui::GetWindowContentRegionWidth() / count - factor; - } - else - { - x = ImGui::GetWindowContentRegionWidth() / count; - } - - return ImVec2(x, ImGui::GetFrameHeight() * 1.3f); -} - -void Ui::CenterdText(const std::string& text) -{ - ImVec2 size = ImGui::CalcTextSize(text.c_str()); - ImGui::NewLine(); - ImGui::SameLine( - ((ImGui::GetWindowContentRegionWidth() - size.x) / 2) - ); - - ImGui::Text(text.c_str()); -} - -void Ui::ShowTooltip(const char* text) -{ - ImGui::SameLine(); - ImGui::TextDisabled("?"); - - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::Text(text); - ImGui::EndTooltip(); - } -} - bool Ui::CheckboxWithHint(const char* label, bool* v, const char* hint, bool is_disabled) { // set things up @@ -344,19 +245,6 @@ bool Ui::CheckboxAddressEx(const char* label, const int addr, int enabled_val, i return rtn; } -bool Ui::CheckboxAddressVar(const char* label, bool val, int addr, const char* hint) -{ - bool rtn = false; - bool state = val; - if (CheckboxWithHint(label, &state, hint)) - { - patch::Set(addr, state, false); - rtn = true; - } - - return rtn; -} - bool Ui::CheckboxBitFlag(const char* label, uint flag, const char* hint) { bool rtn = false; @@ -370,84 +258,6 @@ bool Ui::CheckboxBitFlag(const char* label, uint flag, const char* hint) return rtn; } -void Ui::DrawList(ResourceStore& data, - std::function func_left_click, - std::function func_right_click) -{ - ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - ImGui::GetStyle().ItemSpacing.x)/2); - ListBoxStr("##Categories", data.m_Categories, data.m_Selected); - ImGui::SameLine(); - - data.m_Filter.Draw("##Filter"); - if (strlen(data.m_Filter.InputBuf) == 0) - { - ImDrawList* drawlist = ImGui::GetWindowDrawList(); - - ImVec2 min = ImGui::GetItemRectMin(); - min.x += ImGui::GetStyle().FramePadding.x; - min.y += ImGui::GetStyle().FramePadding.y; - - drawlist->AddText(min, ImGui::GetColorU32(ImGuiCol_TextDisabled), "Search"); - } - - ImGui::PopItemWidth(); - - ImGui::Spacing(); - - if (ImGui::IsMouseClicked(1)) - { - jsonPopup.function = nullptr; - } - - - ImGui::BeginChild(1); - for (auto [k, v] : data.m_pData->Items()) - { - if (k.str() == data.m_Selected || data.m_Selected == "All") - { - for (auto [k2, v2] : v.as_table()->ref()) - { - std::string dataKey = std::string(k2.str()); - if (data.m_Filter.PassFilter(dataKey.c_str())) - { - std::string rootKey = std::string(k.str()); - std::string dataVal = v2.value_or("Unkonwn"); - if (ImGui::MenuItem(dataKey.c_str()) && func_left_click != nullptr) - { - func_left_click(rootKey, dataKey, dataVal); - } - - if (ImGui::IsItemClicked(1) && func_right_click != nullptr) - { - jsonPopup.function = func_right_click; - jsonPopup.root = rootKey; - jsonPopup.key = dataKey; - jsonPopup.value = dataVal; - } - } - } - } - } - - if (jsonPopup.function != nullptr) - { - if (ImGui::BeginPopupContextWindow()) - { - ImGui::Text(jsonPopup.key.c_str()); - ImGui::Separator(); - if (ImGui::MenuItem("Remove")) - jsonPopup.function(jsonPopup.root, jsonPopup.key, jsonPopup.value); - - - if (ImGui::MenuItem("Close")) - jsonPopup.function = nullptr; - - ImGui::EndPopup(); - } - } - ImGui::EndChild(); -} - #ifdef GTASA void Ui::EditStat(const char* label, const int stat_id, const int min, const int def, const int max) { @@ -489,154 +299,6 @@ void Ui::EditStat(const char* label, const int stat_id, const int min, const int } #endif -void Ui::FilterWithHint(const char* label, ImGuiTextFilter& filter, const char* hint) -{ - filter.Draw(label); - - if (strlen(filter.InputBuf) == 0) - { - ImDrawList* drawlist = ImGui::GetWindowDrawList(); - - ImVec2 min = ImGui::GetItemRectMin(); - min.x += ImGui::GetStyle().FramePadding.x; - min.y += ImGui::GetStyle().FramePadding.y; - - drawlist->AddText(min, ImGui::GetColorU32(ImGuiCol_TextDisabled), hint); - } -} - -void Ui::DrawImages(ResourceStore &store, std::function onLeftClick, std::function onRightClick, - std::function getName, std::function verifyFunc, - const char** customNames, size_t length) -{ - ImGuiStyle& style = ImGui::GetStyle(); - /* - Trying to scale images based on resolutions - Native 1366x768 - */ - ImVec2 m_ImageSize = store.m_ImageSize; - m_ImageSize.x *= screen::GetScreenWidth() / 1366.0f; - m_ImageSize.y *= screen::GetScreenHeight() / 768.0f; - - int imageCount = 1; - int imagesInRow = static_cast(ImGui::GetWindowContentRegionWidth() / m_ImageSize.x); - m_ImageSize.x = ImGui::GetWindowContentRegionWidth() - style.ItemSpacing.x * (imagesInRow-1); - m_ImageSize.x /= imagesInRow; - - bool showImages = !Menu::m_bTextOnlyMode; - if (gRenderer == Render_DirectX11) - { - showImages = false; - } - - ImGui::Spacing(); - - // Hide the popup if right clicked again - if (ImGui::IsMouseClicked(1)) - { - imgPopup.function = nullptr; - } - - ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - style.ItemSpacing.x)/2); - if (customNames) - { - ListBoxCustomNames("##Categories", store.m_Selected, customNames, length); - } - else - { - ListBoxStr("##Categories", store.m_Categories, store.m_Selected); - } - - ImGui::SameLine(); - FilterWithHint("##Filter", store.m_Filter, "Search"); - - ImGui::Spacing(); - - ImGui::BeginChild("DrawImages"); - if (showImages) - { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 3)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(3, 3)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(3, 3)); - ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 10.0f); - } - - for (uint i = 0; i < store.m_ImagesList.size(); ++i) - { - std::string text = store.m_ImagesList[i]->m_FileName; - std::string modelName = getName(text); - - if (store.m_Filter.PassFilter(modelName.c_str()) - && (store.m_ImagesList[i]->m_CategoryName == store.m_Selected || store.m_Selected == "All") - && (verifyFunc == nullptr || verifyFunc(text)) - ) - { - /* - Couldn't figure out how to laod images for Dx11 - Using texts for now - */ - if (showImages) - { - if (Ui::RoundedImageButton(store.m_ImagesList[i]->m_pTexture, m_ImageSize, modelName.c_str())) - { - onLeftClick(text); - } - - } - else - { - if (ImGui::MenuItem(modelName.c_str())) - { - onLeftClick(text); - } - } - - // Right click popup - if (ImGui::IsItemClicked(1) && onRightClick != nullptr) - { - imgPopup.function = onRightClick; - imgPopup.value = modelName; - } - - if (showImages) - { - if (imageCount % imagesInRow != 0) - { - ImGui::SameLine(0.0, style.ItemInnerSpacing.x); - } - } - imageCount++; - } - } - - if (showImages) - { - ImGui::PopStyleVar(4); - } - - // Draw popup code - if (imgPopup.function != nullptr) - { - if (ImGui::BeginPopupContextWindow()) - { - ImGui::Text(imgPopup.value.c_str()); - ImGui::Separator(); - if (ImGui::MenuItem("Remove")) - { - imgPopup.function(imgPopup.value); - } - - if (ImGui::MenuItem("Close")) - { - imgPopup.function = nullptr; - } - - ImGui::EndPopup(); - } - } - ImGui::EndChild(); -} - void Ui::RadioButtonAddress(const char* label, std::vector& named_mem) { size_t btn_in_column = named_mem.size() / 2 - 1; diff --git a/src/ui.h b/src/ui.h index d8fa629..70d757b 100644 --- a/src/ui.h +++ b/src/ui.h @@ -17,46 +17,16 @@ public: int value; }; - struct JsonPopUpData - { - std::function function; - std::string key; - std::string root; - std::string value; - }; - - struct ImgPopUpData - { - std::function function; - std::string value; - }; - static inline int m_HeaderId; - static inline JsonPopUpData jsonPopup; - static inline ImgPopUpData imgPopup; - - Ui() = delete; Ui(Ui&) = delete; - static void CenterdText(const std::string& text); static bool ColorButton(int color_id, std::vector& color, ImVec2 size); static bool CheckboxAddress(const char* label, int addr = NULL, const char* hint = nullptr); static bool CheckboxAddressEx(const char* label, int addr = NULL, int enabled_val = 1, int disabled_val = 0, const char* hint = nullptr); - static bool CheckboxAddressVar(const char* label, bool val, int addr, const char* hint = nullptr); - template - static bool CheckboxAddressVarEx(const char* label, int addr, T enabled_val, T disabled_val, const char* hint = nullptr); static bool CheckboxBitFlag(const char* label, uint flag, const char* hint = nullptr); static bool CheckboxWithHint(const char* label, bool* state, const char* hint = nullptr, bool is_disabled = false); - static void DrawList(ResourceStore& data, - std::function func_left_click, - std::function func_right_click); - static void DrawImages(ResourceStore &store, std::function on_left_click, - std::function on_right_click, - std::function get_name_func, - std::function verify_func = nullptr, - const char** custom_names = nullptr, size_t length = 0); static bool DrawTitleBar(); template static void EditAddress(const char* label, int address, int min = 0, int def = 0, int max = 100); @@ -71,42 +41,17 @@ public: static void EditStat(const char* label, int stat_id, int min = 0, int def = 0, int max = 1000); #endif - static void FilterWithHint(const char* label, ImGuiTextFilter& filter, const char* hint); static ImVec2 GetSize(short count = 1, bool spacing = true); static bool ListBox(const char* label, const std::vector& all_items, int& selected); static bool ListBoxStr(const char* label, const std::vector& all_items, std::string& selected); - static bool ListBoxCustomNames(const char* label, std::string& selected, const char* custom_names[] = nullptr, size_t length = 0); static void RadioButtonAddress(const char* label, std::vector& named_mem); static void RadioButtonAddressEx(const char* label, int addr, std::vector& named_val); - static bool RoundedImageButton(ImTextureID user_texture_id, ImVec2& size, const char* hover_text); static void ColorPickerAddress(const char* label, int base_addr, ImVec4&& default_color); - static void ShowTooltip(const char* text); }; -template -bool Ui::CheckboxAddressVarEx(const char* label, int addr, T enabled_val, T disabled_val, const char* hint) -{ - bool rtn = false; - bool state = (patch::Get(addr) == enabled_val); - if (CheckboxWithHint(label, &state, hint)) - { - if (state) - { - patch::Set(addr, enabled_val, false); - } - else - { - patch::Set(addr, disabled_val, false); - } - - rtn = true; - } - - return rtn; -} template void Ui::EditAddress(const char* label, const int address, const int min, const int def, const int max) { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 2c38e39..7ce7bda 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2,6 +2,7 @@ #include "vehicle.h" #include "menu.h" #include "ui.h" +#include "widget.h" #include "util.h" #include "filehandler.h" #include @@ -311,9 +312,9 @@ void WarpPlayerIntoVehicle(CVehicle *pVeh, int seatId) #endif #ifdef GTASA -void Vehicle::SpawnVehicle(const std::string& smodel) +void Vehicle::SpawnVehicle(std::string& smodel) #else -void Vehicle::SpawnVehicle(const std::string& rootkey, const std::string& vehName, const std::string& smodel) +void Vehicle::SpawnVehicle(std::string& rootkey, std::string& vehName, std::string& smodel) #endif { CPlayerPed* player = FindPlayerPed(); @@ -506,7 +507,7 @@ void Vehicle::ShowPage() int hplayer = CPools::GetPedRef(pPlayer); CVehicle *pVeh = pPlayer->m_pVehicle; - if (ImGui::Button(TEXT("Vehicle.BlowCar"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Vehicle.BlowCar"), ImVec2(Widget::CalcSize(3)))) { for (CVehicle *pVeh : CPools::ms_pVehiclePool) { @@ -516,14 +517,14 @@ void Vehicle::ShowPage() ImGui::SameLine(); - if (ImGui::Button(TEXT("Vehicle.FixCar"), ImVec2(Ui::GetSize(3))) && Util::IsInVehicle()) + if (ImGui::Button(TEXT("Vehicle.FixCar"), ImVec2(Widget::CalcSize(3))) && Util::IsInVehicle()) { Util::FixVehicle(pVeh); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Vehicle.FlipCar"), ImVec2(Ui::GetSize(3))) && Util::IsInVehicle()) + if (ImGui::Button(TEXT("Vehicle.FlipCar"), ImVec2(Widget::CalcSize(3))) && Util::IsInVehicle()) { Util::FlipVehicle(pVeh); } @@ -833,7 +834,7 @@ void Vehicle::ShowPage() ImGui::Columns(1); ImGui::Spacing(); - if (ImGui::Button(TEXT("Vehicle.Driver"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Vehicle.Driver"), ImVec2(Widget::CalcSize(2)))) { Command(hplayer, pClosestVeh); } @@ -847,7 +848,7 @@ void Vehicle::ShowPage() } if (ImGui::Button((std::string(TEXT("Vehicle.Passenger")) + std::to_string(i + 1)).c_str(), - ImVec2(Ui::GetSize(2)))) + ImVec2(Widget::CalcSize(2)))) { #ifdef GTASA Command(hplayer, pClosestVeh, i); @@ -870,7 +871,7 @@ void Vehicle::ShowPage() { ImGui::InputInt(TEXT("Vehicle.Radius"), &m_nVehRemoveRadius); ImGui::Spacing(); - if (ImGui::Button(TEXT("Vehicle.RemoveVeh"), Ui::GetSize(1))) + if (ImGui::Button(TEXT("Vehicle.RemoveVeh"), Widget::CalcSize(1))) { CPlayerPed* player = FindPlayerPed(); for (CVehicle* pVeh : CPools::ms_pVehiclePool) @@ -931,7 +932,7 @@ void Vehicle::ShowPage() int doors = seats == 4 ? 6 : 4; int hveh = CPools::GetVehicleRef(pVeh); - if (ImGui::Button(TEXT("Vehicle.All"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Vehicle.All"), ImVec2(Widget::CalcSize()))) { for (int i = 0; i < doors; ++i) { @@ -957,7 +958,7 @@ void Vehicle::ShowPage() for (int i = 0; i != doors; ++i) { - if (ImGui::Button(m_DoorNames[i].c_str(), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(m_DoorNames[i].c_str(), ImVec2(Widget::CalcSize(2)))) { switch (m_nDoorMenuButton) { @@ -998,14 +999,14 @@ void Vehicle::ShowPage() m_fLockSpeed = m_fLockSpeed > 100 ? 100 : m_fLockSpeed; m_fLockSpeed = m_fLockSpeed < 0 ? 0 : m_fLockSpeed; - if (ImGui::Button(TEXT("Vehicle.Set"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Vehicle.Set"), ImVec2(Widget::CalcSize(2)))) { Util::SetCarForwardSpeed(pVeh, m_fLockSpeed); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Vehicle.InstantStop"), ImVec2(Ui::GetSize(2)))) + if (ImGui::Button(TEXT("Vehicle.InstantStop"), ImVec2(Widget::CalcSize(2)))) { Util::SetCarForwardSpeed(pVeh, 0.0f); } @@ -1067,13 +1068,13 @@ void Vehicle::ShowPage() ImGui::SetNextItemWidth(width); ImGui::InputTextWithHint("##LicenseText", TEXT("Vehicle.PlateText"), Spawner::m_nLicenseText, 9); - Ui::DrawImages(Spawner::m_VehData, SpawnVehicle, nullptr, - [](std::string str) + Widget::ImageList(Spawner::m_VehData, SpawnVehicle, nullptr, + [](std::string& str) { return GetNameFromModel(std::stoi(str)); }); #else - Ui::DrawList(Spawner::m_VehData, SpawnVehicle, nullptr); + Widget::DataList(Spawner::m_VehData, SpawnVehicle, nullptr); #endif ImGui::EndTabItem(); } @@ -1088,7 +1089,7 @@ void Vehicle::ShowPage() Paint::GenerateNodeList(veh, PaintData::m_vecNames, PaintData::m_Selected); ImGui::Spacing(); - if (ImGui::Button(TEXT("Vehicle.ResetColor"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Vehicle.ResetColor"), ImVec2(Widget::CalcSize()))) { Paint::ResetNodeColor(veh, PaintData::m_Selected); SetHelpMessage(TEXT("Vehicle.ResetColorMSG")); @@ -1129,7 +1130,7 @@ void Vehicle::ShowPage() int count = (int)m_CarcolsColorData.size(); - ImVec2 size = Ui::GetSize(); + ImVec2 size = Widget::CalcSize(); int btnsInRow = ImGui::GetWindowContentRegionWidth() / (size.y * 2); int btnSize = (ImGui::GetWindowContentRegionWidth() - int(ImGuiStyleVar_ItemSpacing) * (btnsInRow - 0.6 * btnsInRow)) / btnsInRow; @@ -1159,7 +1160,7 @@ void Vehicle::ShowPage() { int model = veh->m_nModelIndex; ImGui::Spacing(); - if (ImGui::Button(TEXT("Vehicle.RemoveNeon"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Vehicle.RemoveNeon"), ImVec2(Widget::CalcSize()))) { Neon::Remove(veh); SetHelpMessage(TEXT("Vehicle.RemoveNeonMSG")); @@ -1195,7 +1196,7 @@ void Vehicle::ShowPage() ImGui::Text(TEXT("Vehicle.SelectPreset")); int count = (int)m_CarcolsColorData.size(); - ImVec2 size = Ui::GetSize(); + ImVec2 size = Widget::CalcSize(); int btnsInRow = ImGui::GetWindowContentRegionWidth() / (size.y * 2); int btnSize = (ImGui::GetWindowContentRegionWidth() - int(ImGuiStyleVar_ItemSpacing) * (btnsInRow - 0.6 * btnsInRow)) / btnsInRow; @@ -1228,7 +1229,7 @@ void Vehicle::ShowPage() Paint::GenerateNodeList(veh, PaintData::m_vecNames, PaintData::m_Selected); ImGui::Spacing(); - if (ImGui::Button(TEXT("Vehicle.ResetTexture"), ImVec2(Ui::GetSize()))) + if (ImGui::Button(TEXT("Vehicle.ResetTexture"), ImVec2(Widget::CalcSize()))) { Paint::ResetNodeTexture(veh, PaintData::m_Selected); SetHelpMessage(TEXT("Vehicle.ResetTextureMSG")); @@ -1274,7 +1275,7 @@ void Vehicle::ShowPage() } ImGui::Columns(1); ImGui::Spacing(); - Ui::DrawImages(Paint::m_TextureData, + Widget::ImageList(Paint::m_TextureData, [](std::string& str) { Paint::SetNodeTexture(FindPlayerPed()->m_pVehicle, PaintData::m_Selected, str, @@ -1292,7 +1293,7 @@ void Vehicle::ShowPage() if (ImGui::BeginTabItem(TEXT("Vehicle.TuneTab"))) { ImGui::Spacing(); - Ui::DrawImages(m_TuneData, + Widget::ImageList(m_TuneData, [](std::string& str) { AddComponent(str); @@ -1305,11 +1306,10 @@ void Vehicle::ShowPage() { return str; }, - [pPlayer](std::string& str) + [](std::string& str) { - return ((bool(*)(int, CVehicle*))0x49B010)(std::stoi(str), pPlayer->m_pVehicle); - } - ); + return ((bool(*)(int, CVehicle*))0x49B010)(std::stoi(str), FindPlayerPed()->m_pVehicle); + }); ImGui::EndTabItem(); } @@ -1322,7 +1322,7 @@ void Vehicle::ShowPage() int handlingID = patch::Get((int)pInfo + 74, false); // CBaseModelInfo + 74 = handlingID tHandlingData *pHandlingData = reinterpret_cast(0xC2B9DC + (handlingID * 224)); // sizeof(tHandlingData) = 224 - if (ImGui::Button(TEXT("Vehicle.ResetHandling"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Vehicle.ResetHandling"), ImVec2(Widget::CalcSize(3)))) { gHandlingDataMgr.LoadHandlingData(); SetHelpMessage(TEXT("Vehicle.ResetHandlingMSG")); @@ -1330,7 +1330,7 @@ void Vehicle::ShowPage() ImGui::SameLine(); - if (ImGui::Button(TEXT("Vehicle.SaveFile"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Vehicle.SaveFile"), ImVec2(Widget::CalcSize(3)))) { FileHandler::GenerateHandlingFile(pHandlingData, m_VehicleIDE); SetHelpMessage(TEXT("Vehicle.SaveFileMSG")); @@ -1338,7 +1338,7 @@ void Vehicle::ShowPage() ImGui::SameLine(); - if (ImGui::Button(TEXT("Vehicle.ReadMore"), ImVec2(Ui::GetSize(3)))) + if (ImGui::Button(TEXT("Vehicle.ReadMore"), ImVec2(Widget::CalcSize(3)))) { ShellExecute(NULL, "open", "https://projectcerbera.com/gta/sa/tutorials/handling", NULL, NULL, SW_SHOWNORMAL); diff --git a/src/vehicle.h b/src/vehicle.h index ef495cf..6521596 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -97,9 +97,9 @@ public: Vehicle(const Vehicle&) = delete; #ifdef GTASA - static void SpawnVehicle(const std::string& name); + static void SpawnVehicle(std::string& name); #else - static void SpawnVehicle(const std::string& rootkey, const std::string& vehName, const std::string& model); + static void SpawnVehicle(std::string& rootkey, std::string& vehName, std::string& model); #endif static void Init(); diff --git a/src/visual.cpp b/src/visual.cpp index 7b615a5..d60d6c5 100644 --- a/src/visual.cpp +++ b/src/visual.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "visual.h" #include "ui.h" +#include "widget.h" #include "util.h" #include "game.h" #include "timecycle.h" @@ -588,7 +589,7 @@ void Visual::ShowPage() ImGui::Spacing(); ImGui::SameLine(); ImGui::TextWrapped(TEXT("Visual.IncompatibleMods")); - Ui::ShowTooltip(TEXT("Visual.IncompatibleModsText")); + Widget::Tooltip(TEXT("Visual.IncompatibleModsText")); ImGui::Spacing(); Ui::ColorPickerAddress(TEXT("Visual.ArmourbarColor"), *(int*)0x5890FC, ImVec4(225, 225, 225, 255)); Ui::EditAddress(TEXT("Visual.ArmourbarPosX"), 0x866B78, -999, 94, 999); @@ -652,13 +653,13 @@ void Visual::ShowPage() #endif { ImGui::Spacing(); - if (ImGui::Button(TEXT("Visual.GenerateFile"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Visual.GenerateFile"), Widget::CalcSize(2))) { GenerateTimecycFile(); SetHelpMessage(TEXT("Visual.FileGenerated")); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Visual.ResetTimecyc"), Ui::GetSize(2))) + if (ImGui::Button(TEXT("Visual.ResetTimecyc"), Widget::CalcSize(2))) { CTimeCycle::Initialise(); SetHelpMessage(TEXT("Visual.TimecycReset")); @@ -703,7 +704,7 @@ void Visual::ShowPage() if (Game::m_bSyncTime) { ImGui::EndDisabled(); - Ui::ShowTooltip(TEXT("Visual.SyncTimeEnabled")); + Widget::Tooltip(TEXT("Visual.SyncTimeEnabled")); } if (ImGui::Checkbox(TEXT("Visual.FreezeGameTime"), &Game::m_bFreezeTime)) diff --git a/src/weapon.cpp b/src/weapon.cpp index 6e15217..3bec172 100644 --- a/src/weapon.cpp +++ b/src/weapon.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "weapon.h" #include "ui.h" +#include "widget.h" #include "util.h" #include "CWeaponInfo.h" @@ -224,7 +225,7 @@ void Weapon::ShowPage() uint hplayer = CPools::GetPedRef(pPlayer); ImGui::Spacing(); - if (ImGui::Button(TEXT("Weapon.DropWeapon"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Weapon.DropWeapon"), Widget::CalcSize(3))) { float x, y, z; Command(hplayer, 0.0, 3.0, 0.0, &x, &y, &z); @@ -248,13 +249,13 @@ void Weapon::ShowPage() } } ImGui::SameLine(); - if (ImGui::Button(TEXT("Weapon.DropAll"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Weapon.DropAll"), Widget::CalcSize(3))) { pPlayer->ClearWeapons(); } ImGui::SameLine(); - if (ImGui::Button(TEXT("Weapon.DropCurrent"), Ui::GetSize(3))) + if (ImGui::Button(TEXT("Weapon.DropCurrent"), Widget::CalcSize(3))) { #ifdef GTASA Command(hplayer, pPlayer->m_aWeapons[pPlayer->m_nActiveWeaponSlot].m_eWeaponType); @@ -273,7 +274,7 @@ void Weapon::ShowPage() ImGui::Spacing(); ImGui::SameLine(); ImGui::Text(TEXT("Window.Info")); - Ui::ShowTooltip(TEXT("Weapon.WeaponTweaksText")); + Widget::Tooltip(TEXT("Weapon.WeaponTweaksText")); ImGui::Columns(2, 0, false); #ifdef GTASA Ui::CheckboxWithHint(TEXT("Weapon.FastAim"), &m_bAutoAim, TEXT("Weapon.FastAimText")); @@ -347,18 +348,17 @@ void Weapon::ShowPage() m_nAmmoCount = (m_nAmmoCount > 99999) ? 99999 : m_nAmmoCount; } #ifdef GTASA - Ui::DrawImages(m_WeaponData, GiveWeaponToPlayer, nullptr, - [](std::string str) + Widget::ImageList(m_WeaponData, GiveWeaponToPlayer, nullptr, + [](std::string& str) { return m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); }, - [](std::string str) + [](std::string& str) { return str != "0"; /*Unarmed*/ - } - ); + }); #else - Ui::DrawList(m_WeaponData, GiveWeaponToPlayer, nullptr); + Widget::DataList(m_WeaponData, GiveWeaponToPlayer, nullptr); #endif ImGui::EndTabItem(); } @@ -380,16 +380,15 @@ void Weapon::ShowPage() std::string key = std::to_string(m_nGangWeaponList[m_nSelectedGang][m_nSelectedWeapon]); ImGui::Text(TEXT("Weapon.CurrentWeapon"), m_WeaponData.m_pData->Get(key.c_str(), "Unknown").c_str()); ImGui::Spacing(); - Ui::DrawImages(m_WeaponData, SetGangWeapon, nullptr, - [](std::string str) + Widget::ImageList(m_WeaponData, SetGangWeapon, nullptr, + [](std::string& str) { - return m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); + return m_WeaponData.m_pData->Get(str.c_str(), "Unknown"); }, - [](std::string str) + [](std::string& str) { return str != "-1"; /*Jetpack*/ - } - ); + }); ImGui::EndTabItem(); } #endif diff --git a/src/weapon.h b/src/weapon.h index dbf3dba..721aad0 100644 --- a/src/weapon.h +++ b/src/weapon.h @@ -30,12 +30,9 @@ private: {WEAPON_UNARMED, WEAPON_UNARMED, WEAPON_UNARMED}, // Gang 9 {WEAPON_UNARMED, WEAPON_UNARMED, WEAPON_UNARMED}, // Gang 10 }; - static inline ResourceStore m_WeaponData { "weapons", eResourceType::TYPE_BOTH, ImVec2(65, 65) }; #else static inline bool m_bInfiniteAmmo; - static inline ResourceStore m_WeaponData { "weapons", eResourceType::TYPE_TEXT }; - #endif public: @@ -46,9 +43,13 @@ public: static void ShowPage(); #ifdef GTASA + static inline ResourceStore m_WeaponData { "weapons", eResourceType::TYPE_IMAGE_TEXT, ImVec2(65, 65) }; + static void GiveWeaponToPlayer(std::string& weapon_type); static void SetGangWeapon(std::string& weapon_type); #else + static inline ResourceStore m_WeaponData { "weapons", eResourceType::TYPE_TEXT }; + static void GiveWeaponToPlayer(std::string& rootkey, std::string& model, std::string& name); #endif }; diff --git a/src/widget.cpp b/src/widget.cpp new file mode 100644 index 0000000..faf8b93 --- /dev/null +++ b/src/widget.cpp @@ -0,0 +1,378 @@ +#include "pch.h" +#include "widget.h" +#include "ui.h" +#include "menu.h" + +static struct +{ + std::string root, key, val; + void* func = nullptr; +} contextMenu; + +ImVec2 Widget::CalcSize(short count, bool spacing) +{ + if (count == 1) + { + spacing = false; + } + + // manually tested values + float factor = ImGui::GetStyle().ItemSpacing.x / 2.0f; + float x; + + if (count == 3) + { + factor = ImGui::GetStyle().ItemSpacing.x / 1.403f; + } + + if (spacing) + { + x = ImGui::GetWindowContentRegionWidth() / count - factor; + } + else + { + x = ImGui::GetWindowContentRegionWidth() / count; + } + + return ImVec2(x, ImGui::GetFrameHeight() * 1.3f); +} + +void Widget::TextCentered(const std::string& text) +{ + ImVec2 size = ImGui::CalcTextSize(text.c_str()); + ImGui::NewLine(); + float width = ImGui::GetWindowContentRegionWidth() - size.x; + ImGui::SameLine(width/2); + ImGui::Text(text.c_str()); +} + +void Widget::Tooltip(const char* text) +{ + ImGui::SameLine(); + ImGui::TextDisabled("?"); + + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text(text); + ImGui::EndTooltip(); + } +} + +void Widget::FilterWithHint(const char* label, ImGuiTextFilter& filter, const char* hint) +{ + filter.Draw(label); + + if (strlen(filter.InputBuf) == 0) + { + ImDrawList* drawlist = ImGui::GetWindowDrawList(); + + ImVec2 min = ImGui::GetItemRectMin(); + min.x += ImGui::GetStyle().FramePadding.x; + min.y += ImGui::GetStyle().FramePadding.y; + + drawlist->AddText(min, ImGui::GetColorU32(ImGuiCol_TextDisabled), hint); + } +} + +void Widget::DataList(ResourceStore& data, ArgCallback3 clickFunc, ArgCallback3 removeFunc) +{ + if (ImGui::IsMouseClicked(1)) + { + contextMenu.func = nullptr; + } + + // Drawing the list here + if (ImGui::BeginTabBar("MYTABS")) + { + if (ImGui::BeginTabItem(TEXT("Window.Search"))) + { + ImGui::Spacing(); + // Category box + ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - ImGui::GetStyle().ItemSpacing.x)/2); + Ui::ListBoxStr("##Categories", data.m_Categories, data.m_Selected); + + ImGui::SameLine(); + + // Search box + data.m_Filter.Draw("##Filter"); + if (strlen(data.m_Filter.InputBuf) == 0) + { + ImDrawList* drawlist = ImGui::GetWindowDrawList(); + + ImVec2 min = ImGui::GetItemRectMin(); + min.x += ImGui::GetStyle().FramePadding.x; + min.y += ImGui::GetStyle().FramePadding.y; + + drawlist->AddText(min, ImGui::GetColorU32(ImGuiCol_TextDisabled), "Search"); + } + ImGui::PopItemWidth(); + + ImGui::Spacing(); + ImGui::BeginChild(1); + for (auto [k, v] : data.m_pData->Items()) + { + if (k.str() == data.m_Selected || data.m_Selected == "All") + { + for (auto [k2, v2] : v.as_table()->ref()) + { + std::string key = std::string(k2.str()); + if (data.m_Filter.PassFilter(key.c_str())) + { + std::string root = std::string(k.str()); + std::string val = v2.value_or("Unkonwn"); + if (ImGui::MenuItem(key.c_str()) && clickFunc != nullptr) + { + clickFunc(root, key, val); + } + + if (ImGui::IsItemClicked(1)) + { + contextMenu = {root, key, val, removeFunc}; + } + } + } + } + } + if (contextMenu.func != nullptr) + { + if (ImGui::BeginPopupContextWindow()) + { + ImGui::Text(contextMenu.key.c_str()); + ImGui::Separator(); + if (ImGui::MenuItem(TEXT("Menu.Favourites"))) + { + data.m_pData->Set(std::format("Favourites.{}", contextMenu.key).c_str(), contextMenu.val); + data.m_pData->Save(); + SetHelpMessage(TEXT("Menu.FavouritesText")); + } + if (ImGui::MenuItem(TEXT("Menu.Remove"))) + { + static_cast(contextMenu.func)(contextMenu.root, contextMenu.key, contextMenu.val); + } + if (ImGui::MenuItem(TEXT("Menu.Close"))) + { + contextMenu.func = nullptr; + } + + ImGui::EndPopup(); + } + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem(TEXT("Window.FavouritesTab"))) + { + ImGui::Spacing(); + ImGui::BeginChild(1); + for (auto [k, v] : *data.m_pData->GetTable("Favourites")) + { + std::string key = std::string(k.str()); + if (data.m_Filter.PassFilter(key.c_str())) + { + std::string val = v.value_or("Unkonwn"); + if (ImGui::MenuItem(key.c_str()) && clickFunc != nullptr) + { + std::string str = "Favourites"; + clickFunc(str, key, val); + } + + if (ImGui::IsItemClicked(1)) + { + contextMenu = {std::string("Favourites"), key, val}; + } + } + } + if (contextMenu.func != nullptr) + { + if (ImGui::BeginPopupContextWindow()) + { + ImGui::Text(contextMenu.key.c_str()); + ImGui::Separator(); + if (ImGui::MenuItem(TEXT("Menu.FavouritesRemove"))) + { + data.m_pData->RemoveKey("Favourites", contextMenu.key.c_str()); + data.m_pData->Save(); + SetHelpMessage(TEXT("Menu.FavouritesRemoveText")); + } + if (ImGui::MenuItem(TEXT("Menu.Close"))) + { + contextMenu.func = nullptr; + } + + ImGui::EndPopup(); + } + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } +} + +static bool RoundedImageButton(ImTextureID user_texture_id, ImVec2& size, const char* hover_text) +{ + // Default to using texture ID as ID. User can still push string/integer prefixes. + + // Creating a invisible button as placeholder + ImGui::InvisibleButton(hover_text, size); + ImVec2 min = ImGui::GetItemRectMin(); + ImVec2 max = ImGui::GetItemRectMax(); + ImDrawList *drawList = ImGui::GetWindowDrawList(); + drawList->AddImageRounded(user_texture_id, min, max, ImVec2(0, 0), ImVec2(1, 1), ImGui::GetColorU32(ImVec4(1, 1, 1, 1)), 5.0f); + + // Add selection overlay and stuff on hover + if (ImGui::IsItemHovered()) + { + drawList->AddRectFilled(min, max, ImGui::GetColorU32(ImGuiCol_ModalWindowDimBg), 5.6f); + + // Calculating and drawing text over the image + ImVec2 textSize = ImGui::CalcTextSize(hover_text); + if (textSize.x < size.x) + { + float offsetX = (ImGui::GetItemRectSize().x - textSize.x) / 2; + drawList->AddText(ImVec2(min.x + offsetX, min.y + 10), ImGui::GetColorU32(ImGuiCol_Text), hover_text); + } + else + { + std::string buf = ""; + std::stringstream ss(hover_text); + short count = 1; + + while (ss >> buf) + { + textSize = ImGui::CalcTextSize(buf.c_str()); + float offsetX = (ImGui::GetItemRectSize().x - textSize.x) / 2; + drawList->AddText(ImVec2(min.x + offsetX, min.y + 10 * count), + ImGui::GetColorU32(ImGuiCol_Text), buf.c_str()); + ++count; + } + } + } + + return ImGui::IsItemClicked(0); +} + +void Widget::ImageList(ResourceStore &store, ArgCallback leftClickFunc, ArgCallback rightClickFunc, + ArgCallbackRtn getNameFunc, ArgCallbackRtnBool verifyFunc) +{ + ImGuiStyle& style = ImGui::GetStyle(); + /* + Trying to scale images based on resolutions + Native 1366x768 + */ + ImVec2 m_ImageSize = store.m_ImageSize; + m_ImageSize.x *= screen::GetScreenWidth() / 1366.0f; + m_ImageSize.y *= screen::GetScreenHeight() / 768.0f; + + int imageCount = 1; + int imagesInRow = static_cast(ImGui::GetWindowContentRegionWidth() / m_ImageSize.x); + m_ImageSize.x = ImGui::GetWindowContentRegionWidth() - style.ItemSpacing.x * (imagesInRow-1); + m_ImageSize.x /= imagesInRow; + + bool showImages = !Menu::m_bTextOnlyMode; + if (gRenderer == Render_DirectX11) + { + showImages = false; + } + + ImGui::Spacing(); + + // Hide the popup if right clicked again + if (ImGui::IsMouseClicked(1)) + { + contextMenu.func = nullptr; + } + + ImGui::PushItemWidth((ImGui::GetWindowContentRegionWidth() - style.ItemSpacing.x)/2); + Ui::ListBoxStr("##Categories", store.m_Categories, store.m_Selected); + ImGui::SameLine(); + FilterWithHint("##Filter", store.m_Filter, "Search"); + + ImGui::Spacing(); + + ImGui::BeginChild("DrawImages"); + if (showImages) + { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3, 3)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(3, 3)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(3, 3)); + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 10.0f); + } + + // Draw images here + for (uint i = 0; i < store.m_ImagesList.size(); ++i) + { + std::string text = store.m_ImagesList[i]->m_FileName; + std::string modelName = getNameFunc(text); + + if (store.m_Filter.PassFilter(modelName.c_str()) + && (store.m_ImagesList[i]->m_CategoryName == store.m_Selected || store.m_Selected == "All") + && (verifyFunc == nullptr || verifyFunc(text)) + ) + { + /* + Couldn't figure out how to laod images for Dx11 + Using texts for now + */ + if (showImages) + { + if (RoundedImageButton(store.m_ImagesList[i]->m_pTexture, m_ImageSize, modelName.c_str())) + { + leftClickFunc(text); + } + + } + else + { + if (ImGui::MenuItem(modelName.c_str())) + { + leftClickFunc(text); + } + } + + // Right click popup + if (ImGui::IsItemClicked(1) && rightClickFunc != nullptr) + { + contextMenu.func = rightClickFunc; + contextMenu.val = modelName; + } + + if (showImages) + { + if (imageCount % imagesInRow != 0) + { + ImGui::SameLine(0.0, style.ItemInnerSpacing.x); + } + } + imageCount++; + } + } + + if (showImages) + { + ImGui::PopStyleVar(4); + } + + // Draw popup code + if (contextMenu.func != nullptr) + { + if (ImGui::BeginPopupContextWindow()) + { + ImGui::Text(contextMenu.val.c_str()); + ImGui::Separator(); + if (ImGui::MenuItem("Remove")) + { + static_cast(contextMenu.func)(contextMenu.val); + } + + if (ImGui::MenuItem("Close")) + { + contextMenu.func = nullptr; + } + + ImGui::EndPopup(); + } + } + ImGui::EndChild(); +} \ No newline at end of file diff --git a/src/widget.h b/src/widget.h new file mode 100644 index 0000000..b2cd24a --- /dev/null +++ b/src/widget.h @@ -0,0 +1,35 @@ +#pragma once +#include "pch.h" + +/* + Widgets Class + Contains useful ui utilities + +TODO: + Replace the horrible Ui class +*/ +class Widget +{ +public: + Widget() = delete; + Widget(Widget&) = delete; + + // Calculates button size based on window width & spacing flags + static ImVec2 CalcSize(short count = 1, bool spacing = true); + + // Draws DataStore data in the interface + static void DataList(ResourceStore& data, ArgCallback3 clickFunc, ArgCallback3 removeFunc); + + // ImGui::TextFilter with hint support + static void FilterWithHint(const char* label, ImGuiTextFilter& filter, const char* hint); + + // Draws ResourceStore images in the interface + static void ImageList(ResourceStore &store, ArgCallback leftClickFunc, ArgCallback rightClickFunc, + ArgCallbackRtn getNameFunc, ArgCallbackRtnBool verifyFunc = nullptr); + + // Text aligned to the center of the window + static void TextCentered(const std::string& text); + + // Displays a popup with helpful text + static void Tooltip(const char* text); +}; \ No newline at end of file