mirror of
https://github.com/YimMenu/YimMenuV2.git
synced 2026-10-10 03:43:15 +08:00
(UI) Modular Theme + ImGui Color/Rounding settings for Menu Customization (#551)
* (UI) Modular Theme - Added Modular Theme - Moved SetupStyle function to Themes.cpp for future impl - Ensured all themes use proper colore using ImGui::GetColorU32 to pull colors used in SetupStyle() * (UI) Small change * (UI) Implemented Color/Transparency/Rounding for all ImGui Elements. - Adds a file (GUISettings.json) to the appdata which saves/loads the custom colors, falls back to default if the file does not exist. * (UI) Added more customization abilities - This adds Layout, Borders and Global options for ImGui customization - Fixed some mismatched colors on buttons * (UI) Altered category name * (UI) Added more ImGui customization tabs - Moved default theme to DefaultStyle function * (UI) Fixed Exceptions in console thanks to Mr-X * small fix * (Fix) Font scaling - Removed rebuild fonts, useless for now * Added Helper Functions to utilize FloatCommand and minimize a bulky list Added PrettyPrintLabel to automatically print the slider labels accordingly * Ensured all settings save to GUISettings.json
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "Command.hpp"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
@@ -9,8 +8,6 @@ namespace YimMenu
|
||||
protected:
|
||||
virtual void OnChange() {};
|
||||
virtual void OnCall() override;
|
||||
virtual void SaveState(nlohmann::json& value) override;
|
||||
virtual void LoadState(nlohmann::json& value) override;
|
||||
|
||||
ImVec4 m_State = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
@@ -18,5 +15,7 @@ namespace YimMenu
|
||||
ColorCommand(std::string name, std::string label, std::string description, ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
ImVec4 GetState();
|
||||
void SetState(ImVec4 state);
|
||||
virtual void SaveState(nlohmann::json& value) override;
|
||||
virtual void LoadState(nlohmann::json& value) override;
|
||||
};
|
||||
}
|
||||
@@ -9,16 +9,15 @@ namespace YimMenu
|
||||
class Command
|
||||
{
|
||||
private:
|
||||
std::string m_Name;
|
||||
std::string m_Label;
|
||||
std::string m_Description;
|
||||
joaat_t m_Hash;
|
||||
|
||||
int m_NumArgs = 0; // TODO: currently unused
|
||||
|
||||
protected:
|
||||
virtual void OnCall() = 0;
|
||||
void MarkDirty();
|
||||
std::string m_Name;
|
||||
std::string m_Label;
|
||||
std::string m_Description;
|
||||
joaat_t m_Hash;
|
||||
|
||||
public:
|
||||
Command(std::string name, std::string label, std::string description, int num_args = 0);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace YimMenu::Features
|
||||
{0, "Classic"},
|
||||
{1, "Modern"},
|
||||
{2, "Modern (Vertical)"},
|
||||
{3, "Modern (Modular)"},
|
||||
};
|
||||
|
||||
// Expose as global reference so other code can use it
|
||||
@@ -51,6 +52,9 @@ namespace YimMenu
|
||||
case UITheme::ModernV:
|
||||
RenderModernVTheme();
|
||||
break;
|
||||
case UITheme::Modular:
|
||||
RenderModularTheme();
|
||||
break;
|
||||
default:
|
||||
RenderClassicTheme(); // Default theme
|
||||
break;
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace YimMenu
|
||||
Classic = 0,
|
||||
Modern,
|
||||
ModernV,
|
||||
Modular,
|
||||
};
|
||||
|
||||
class UIManager
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "game/frontend/Menu.hpp"
|
||||
#include "core/frontend/manager/UIManager.hpp"
|
||||
#include "game/frontend/submenus/Settings/GUISettings.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void RenderClassicTheme()
|
||||
{
|
||||
YimMenu::SyncColorCommandsToStyle();
|
||||
|
||||
float windowWidth = *YimMenu::Pointers.ScreenResX / 2.5f;
|
||||
float centerX = (*YimMenu::Pointers.ScreenResX - windowWidth) / 2.0f;
|
||||
float centerY = *YimMenu::Pointers.ScreenResY / 5.0f;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "game/frontend/Menu.hpp"
|
||||
#include "core/frontend/manager/UIManager.hpp"
|
||||
#include "game/frontend/submenus/Settings/GUISettings.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void RenderModernTheme()
|
||||
{
|
||||
YimMenu::SyncColorCommandsToStyle();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
@@ -26,6 +29,8 @@ namespace YimMenu
|
||||
ImGui::Begin("##BubbleInputWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoBringToFrontOnFocus);
|
||||
|
||||
const auto& submenus = YimMenu::UIManager::GetSubmenus();
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
|
||||
for (size_t i = 0; i < submenus.size(); ++i)
|
||||
{
|
||||
auto& submenu = submenus[i];
|
||||
@@ -35,27 +40,14 @@ namespace YimMenu
|
||||
ImGui::SetCursorScreenPos(bubblePos);
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
|
||||
ImVec2 bgPos(center.x - bgSize / 2.0f, center.y - bgSize / 2.0f);
|
||||
drawList->AddRectFilled(bgPos, ImVec2(bgPos.x + bgSize, bgPos.y + bgSize), IM_COL32(10, 10, 10, 255), rounding);
|
||||
drawList->AddRect(bgPos, ImVec2(bgPos.x + bgSize, bgPos.y + bgSize), IM_COL32(192, 192, 192, 32), rounding, ImDrawFlags_None, 1.0f);
|
||||
|
||||
ImU32 bubbleColor = IM_COL32(25, 25, 31, 255);
|
||||
ImU32 hoverColor = IM_COL32(46, 46, 51, 255);
|
||||
ImGui::InvisibleButton("##Bubble", ImVec2(bubbleSize, bubbleSize));
|
||||
bool hovered = ImGui::IsItemHovered();
|
||||
bool clicked = ImGui::IsItemClicked();
|
||||
|
||||
drawList->AddRectFilled(bubblePos, ImVec2(bubblePos.x + bubbleSize, bubblePos.y + bubbleSize), hovered ? hoverColor : bubbleColor, rounding);
|
||||
drawList->AddRect(bubblePos, ImVec2(bubblePos.x + bubbleSize, bubblePos.y + bubbleSize), IM_COL32(192, 192, 192, 16), rounding, ImDrawFlags_None, 1.0f);
|
||||
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
|
||||
if (clicked)
|
||||
{
|
||||
if (submenu == activeSubmenu)
|
||||
{
|
||||
YimMenu::UIManager::SetShowContentWindow(!YimMenu::UIManager::ShowingContentWindow());
|
||||
}
|
||||
else
|
||||
{
|
||||
YimMenu::UIManager::SetActiveSubmenu(submenu);
|
||||
@@ -63,34 +55,39 @@ namespace YimMenu
|
||||
}
|
||||
}
|
||||
|
||||
ImU32 defaultIconColor = IM_COL32(255, 255, 255, 255);
|
||||
ImU32 activeIconColor = IM_COL32(46, 204, 113, 255);
|
||||
ImU32 hoveredIconColor = IM_COL32(36, 174, 93, 255);
|
||||
ImU32 iconColor = submenu == activeSubmenu ? activeIconColor : (hovered ? hoveredIconColor : defaultIconColor);
|
||||
// Colors
|
||||
ImU32 buttonColor = ImGui::GetColorU32(ImGuiCol_Button);
|
||||
ImU32 hoverColor = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
|
||||
ImU32 activeColor = ImGui::GetColorU32(ImGuiCol_ButtonActive);
|
||||
ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border);
|
||||
ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
|
||||
ImU32 fillColor = (submenu == activeSubmenu) ? activeColor : (hovered ? hoverColor : buttonColor);
|
||||
|
||||
// Bubble background and border
|
||||
drawList->AddRectFilled(bubblePos, bubblePos + ImVec2(bubbleSize, bubbleSize), fillColor, rounding);
|
||||
drawList->AddRect(bubblePos, bubblePos + ImVec2(bubbleSize, bubbleSize), borderColor, rounding);
|
||||
|
||||
// Icon (text color only)
|
||||
ImGui::PushFont(YimMenu::Menu::Font::g_AwesomeFont);
|
||||
ImVec2 iconSize = ImGui::CalcTextSize(submenu->m_Icon.c_str());
|
||||
ImVec2 iconPos(center.x - iconSize.x / 2, center.y - iconSize.y / 2);
|
||||
drawList->AddText(YimMenu::Menu::Font::g_AwesomeFont, 0.0f, iconPos, iconColor, submenu->m_Icon.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImU32 defaultTextColor = IM_COL32(255, 255, 255, 255);
|
||||
ImU32 activeTextColor = IM_COL32(46, 204, 113, 255);
|
||||
ImU32 hoveredTextColor = IM_COL32(36, 174, 93, 255);
|
||||
ImU32 textColor = submenu == activeSubmenu ? activeTextColor : (hovered ? hoveredTextColor : defaultTextColor);
|
||||
|
||||
// Label
|
||||
ImVec2 labelSize = ImGui::CalcTextSize(submenu->m_Name.c_str());
|
||||
ImVec2 labelPos(center.x - labelSize.x / 2, bubblePos.y + bubbleSize + 15.0f);
|
||||
ImVec2 bgMin = labelPos - ImVec2(6, 2);
|
||||
ImVec2 bgMax = labelPos + labelSize + ImVec2(6, 2);
|
||||
|
||||
drawList->AddRectFilled(bgMin, bgMax, IM_COL32(26, 26, 31, 120));
|
||||
drawList->AddRect(bgMin, bgMax, IM_COL32(192, 192, 192, 16), 4.0f);
|
||||
drawList->AddText(labelPos, textColor, submenu->m_Name.c_str());
|
||||
drawList->AddRectFilled(bgMin, bgMax, ImGui::GetColorU32(ImGuiCol_ChildBg));
|
||||
drawList->AddRect(bgMin, bgMax, borderColor, 4.0f);
|
||||
drawList->AddText(labelPos, iconColor, submenu->m_Name.c_str());
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Drag zone
|
||||
ImVec2 dragZoneMin = ImVec2(basePos.x, basePos.y - 20);
|
||||
ImVec2 dragZoneMax = ImVec2(basePos.x + bubbleSpacing * submenus.size(), basePos.y + bubbleSize);
|
||||
ImGui::SetCursorScreenPos(dragZoneMin);
|
||||
@@ -106,8 +103,7 @@ namespace YimMenu
|
||||
else
|
||||
{
|
||||
ImVec2 delta = io.MousePos - dragStart;
|
||||
basePosOffset.x += delta.x;
|
||||
basePosOffset.y += delta.y;
|
||||
basePosOffset += delta;
|
||||
dragStart = io.MousePos;
|
||||
}
|
||||
}
|
||||
@@ -116,10 +112,9 @@ namespace YimMenu
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
ImGui::End(); // ##BubbleInputWindow
|
||||
|
||||
// Content window
|
||||
if (YimMenu::UIManager::ShowingContentWindow() && activeSubmenu)
|
||||
{
|
||||
float windowWidth = *YimMenu::Pointers.ScreenResX / 2.5f;
|
||||
@@ -129,14 +124,13 @@ namespace YimMenu
|
||||
|
||||
ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(centerX, centerY), ImGuiCond_FirstUseEver);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse;
|
||||
|
||||
if (ImGui::Begin("##Categories&Content", nullptr, flags))
|
||||
{
|
||||
if (ImGui::BeginChild("##categorySelectors", ImVec2(0, 60), true))
|
||||
{
|
||||
activeSubmenu->DrawCategorySelectors();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (ImGui::BeginChild("##options", ImVec2(0, 0), true))
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "game/frontend/Menu.hpp"
|
||||
#include "core/frontend/manager/UIManager.hpp"
|
||||
#include "game/frontend/submenus/Settings/GUISettings.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void RenderModernVTheme()
|
||||
{
|
||||
YimMenu::SyncColorCommandsToStyle();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
||||
|
||||
@@ -26,37 +29,27 @@ namespace YimMenu
|
||||
ImGui::Begin("##BubbleInputWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoBringToFrontOnFocus);
|
||||
|
||||
const auto& submenus = YimMenu::UIManager::GetSubmenus();
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
|
||||
for (size_t i = 0; i < submenus.size(); ++i)
|
||||
{
|
||||
auto& submenu = submenus[i];
|
||||
// Changed horizontal to vertical:
|
||||
|
||||
ImVec2 bubblePos(basePos.x, basePos.y + i * bubbleSpacing + 2);
|
||||
ImVec2 center(bubblePos.x + bubbleSize / 2.0f, bubblePos.y + bubbleSize / 2.0f);
|
||||
|
||||
ImGui::SetCursorScreenPos(bubblePos);
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
|
||||
ImVec2 bgPos(center.x - bgSize / 2.0f, center.y - bgSize / 2.0f);
|
||||
drawList->AddRectFilled(bgPos, ImVec2(bgPos.x + bgSize, bgPos.y + bgSize), IM_COL32(10, 10, 10, 255), rounding);
|
||||
drawList->AddRect(bgPos, ImVec2(bgPos.x + bgSize, bgPos.y + bgSize), IM_COL32(192, 192, 192, 32), rounding, ImDrawFlags_None, 1.0f);
|
||||
|
||||
ImU32 bubbleColor = IM_COL32(25, 25, 31, 255);
|
||||
ImU32 hoverColor = IM_COL32(46, 46, 51, 255);
|
||||
// Invisible button logic
|
||||
ImGui::InvisibleButton("##Bubble", ImVec2(bubbleSize, bubbleSize));
|
||||
bool hovered = ImGui::IsItemHovered();
|
||||
bool clicked = ImGui::IsItemClicked();
|
||||
|
||||
drawList->AddRectFilled(bubblePos, ImVec2(bubblePos.x + bubbleSize, bubblePos.y + bubbleSize), hovered ? hoverColor : bubbleColor, rounding);
|
||||
drawList->AddRect(bubblePos, ImVec2(bubblePos.x + bubbleSize, bubblePos.y + bubbleSize), IM_COL32(192, 192, 192, 16), rounding, ImDrawFlags_None, 1.0f);
|
||||
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
|
||||
if (clicked)
|
||||
{
|
||||
if (submenu == activeSubmenu)
|
||||
{
|
||||
YimMenu::UIManager::SetShowContentWindow(!YimMenu::UIManager::ShowingContentWindow());
|
||||
}
|
||||
else
|
||||
{
|
||||
YimMenu::UIManager::SetActiveSubmenu(submenu);
|
||||
@@ -64,34 +57,40 @@ namespace YimMenu
|
||||
}
|
||||
}
|
||||
|
||||
ImU32 defaultIconColor = IM_COL32(255, 255, 255, 255);
|
||||
ImU32 activeIconColor = IM_COL32(46, 204, 113, 255);
|
||||
ImU32 hoveredIconColor = IM_COL32(36, 174, 93, 255);
|
||||
ImU32 iconColor = submenu == activeSubmenu ? activeIconColor : (hovered ? hoveredIconColor : defaultIconColor);
|
||||
// Colors from ImGui style
|
||||
ImU32 buttonColor = ImGui::GetColorU32(ImGuiCol_Button);
|
||||
ImU32 hoverColor = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
|
||||
ImU32 activeColor = ImGui::GetColorU32(ImGuiCol_ButtonActive);
|
||||
ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border);
|
||||
ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
|
||||
// Final fill color
|
||||
ImU32 fillColor = (submenu == activeSubmenu) ? activeColor : (hovered ? hoverColor : buttonColor);
|
||||
|
||||
// Draw filled button bubble
|
||||
drawList->AddRectFilled(bubblePos, bubblePos + ImVec2(bubbleSize, bubbleSize), fillColor, rounding);
|
||||
drawList->AddRect(bubblePos, bubblePos + ImVec2(bubbleSize, bubbleSize), borderColor, rounding, ImDrawFlags_None, 1.0f);
|
||||
|
||||
// Draw icon centered (text color always)
|
||||
ImGui::PushFont(YimMenu::Menu::Font::g_AwesomeFont);
|
||||
ImVec2 iconSize = ImGui::CalcTextSize(submenu->m_Icon.c_str());
|
||||
ImVec2 iconPos(center.x - iconSize.x / 2, center.y - iconSize.y / 2);
|
||||
drawList->AddText(YimMenu::Menu::Font::g_AwesomeFont, 0.0f, iconPos, iconColor, submenu->m_Icon.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImU32 defaultTextColor = IM_COL32(255, 255, 255, 255);
|
||||
ImU32 activeTextColor = IM_COL32(46, 204, 113, 255);
|
||||
ImU32 hoveredTextColor = IM_COL32(36, 174, 93, 255);
|
||||
ImU32 textColor = submenu == activeSubmenu ? activeTextColor : (hovered ? hoveredTextColor : defaultTextColor);
|
||||
|
||||
// Draw label below bubble
|
||||
ImVec2 labelSize = ImGui::CalcTextSize(submenu->m_Name.c_str());
|
||||
ImVec2 labelPos(center.x - labelSize.x / 2, bubblePos.y + bubbleSize + 15.0f);
|
||||
ImVec2 bgMin = labelPos - ImVec2(6, 2);
|
||||
ImVec2 bgMax = labelPos + labelSize + ImVec2(6, 2);
|
||||
|
||||
drawList->AddRectFilled(bgMin, bgMax, IM_COL32(26, 26, 31, 120));
|
||||
drawList->AddRect(bgMin, bgMax, IM_COL32(192, 192, 192, 16), 4.0f);
|
||||
drawList->AddText(labelPos, textColor, submenu->m_Name.c_str());
|
||||
drawList->AddRectFilled(bgMin, bgMax, ImGui::GetColorU32(ImGuiCol_ChildBg));
|
||||
drawList->AddRect(bgMin, bgMax, borderColor, 4.0f);
|
||||
drawList->AddText(labelPos, iconColor, submenu->m_Name.c_str());
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Drag zone (optional repositioning)
|
||||
ImVec2 dragZoneMin = ImVec2(basePos.x + bubbleSize + 10, basePos.y);
|
||||
ImVec2 dragZoneMax = ImVec2(basePos.x + bubbleSize + 10 + bubbleSpacing, basePos.y + bubbleSpacing * submenus.size());
|
||||
ImGui::SetCursorScreenPos(dragZoneMin);
|
||||
@@ -107,8 +106,7 @@ namespace YimMenu
|
||||
else
|
||||
{
|
||||
ImVec2 delta = io.MousePos - dragStart;
|
||||
basePosOffset.x += delta.x;
|
||||
basePosOffset.y += delta.y;
|
||||
basePosOffset += delta;
|
||||
dragStart = io.MousePos;
|
||||
}
|
||||
}
|
||||
@@ -119,8 +117,7 @@ namespace YimMenu
|
||||
|
||||
ImGui::End();
|
||||
|
||||
auto activeSubmenu = YimMenu::UIManager::GetActiveSubmenu();
|
||||
|
||||
// Content window
|
||||
if (YimMenu::UIManager::ShowingContentWindow() && activeSubmenu)
|
||||
{
|
||||
float windowWidth = *YimMenu::Pointers.ScreenResX / 2.5f;
|
||||
@@ -130,14 +127,11 @@ namespace YimMenu
|
||||
|
||||
ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(centerX, centerY), ImGuiCond_FirstUseEver);
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse;
|
||||
|
||||
if (ImGui::Begin("##Categories&Content", nullptr, flags))
|
||||
if (ImGui::Begin("##Categories&Content", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse))
|
||||
{
|
||||
if (ImGui::BeginChild("##categorySelectors", ImVec2(0, 60), true))
|
||||
{
|
||||
activeSubmenu->DrawCategorySelectors();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (ImGui::BeginChild("##options", ImVec2(0, 0), true))
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#include <algorithm>
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "game/frontend/Menu.hpp"
|
||||
#include "core/frontend/manager/UIManager.hpp"
|
||||
#include "game/frontend/submenus/Settings/GUISettings.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void RenderModularTheme()
|
||||
{
|
||||
YimMenu::SyncColorCommandsToStyle();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
||||
const auto& submenus = UIManager::GetSubmenus();
|
||||
auto activeSubmenu = UIManager::GetActiveSubmenu();
|
||||
|
||||
const float bubblePadding = 10.0f;
|
||||
const float leftOffset = 25.0f;
|
||||
const float topOffset = 25.0f;
|
||||
const float defaultWidth = 80.0f;
|
||||
const float defaultHeight = 80.0f;
|
||||
|
||||
for (size_t i = 0; i < submenus.size(); ++i)
|
||||
{
|
||||
auto& submenu = submenus[i];
|
||||
std::string windowId = "NavItem_" + submenu->m_Name;
|
||||
|
||||
ImVec2 startPos(leftOffset, topOffset + i * (defaultHeight + bubblePadding));
|
||||
ImVec2 defaultSize(defaultWidth, defaultHeight);
|
||||
|
||||
ImGui::SetNextWindowPos(startPos, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(defaultSize, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(60, 80), ImVec2(200, 200));
|
||||
ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background
|
||||
|
||||
if (ImGui::Begin(windowId.c_str(), nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
ImVec2 winPos = ImGui::GetWindowPos();
|
||||
ImVec2 winSize = ImGui::GetWindowSize();
|
||||
ImVec2 center(winPos.x + winSize.x / 2, winPos.y + winSize.y / 2 - 10);
|
||||
|
||||
ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border);
|
||||
ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
ImU32 buttonColor = ImGui::GetColorU32(ImGuiCol_Button);
|
||||
ImU32 hoverColor = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
|
||||
ImU32 activeColor = ImGui::GetColorU32(ImGuiCol_ButtonActive);
|
||||
|
||||
ImVec2 bubbleSize = winSize - ImVec2(20, 30);
|
||||
ImVec2 bubblePos(winPos.x + (winSize.x - bubbleSize.x) / 2, winPos.y + 10);
|
||||
|
||||
ImGui::SetCursorScreenPos(bubblePos);
|
||||
ImGui::InvisibleButton(("##bubble_" + submenu->m_Name).c_str(), bubbleSize);
|
||||
bool hovered = ImGui::IsItemHovered();
|
||||
bool clicked = ImGui::IsItemClicked();
|
||||
|
||||
if (clicked)
|
||||
{
|
||||
if (activeSubmenu == submenu)
|
||||
UIManager::SetShowContentWindow(!UIManager::ShowingContentWindow());
|
||||
else
|
||||
{
|
||||
UIManager::SetActiveSubmenu(submenu);
|
||||
UIManager::SetShowContentWindow(true);
|
||||
}
|
||||
}
|
||||
|
||||
ImU32 bubbleBgColor = (submenu == activeSubmenu) ? activeColor : (hovered ? hoverColor : buttonColor);
|
||||
// Button
|
||||
drawList->AddRectFilled(bubblePos, bubblePos + bubbleSize, bubbleBgColor, 10.0f);
|
||||
drawList->AddRect(bubblePos, bubblePos + bubbleSize, borderColor, 10.0f, 0, 1.5f);
|
||||
|
||||
// Icon
|
||||
ImGui::PushFont(Menu::Font::g_AwesomeFont);
|
||||
float iconScale = std::clamp(bubbleSize.y * 0.4f, 14.0f, 32.0f);
|
||||
ImVec2 iconSize = ImGui::CalcTextSize(submenu->m_Icon.c_str());
|
||||
ImVec2 iconPos(center.x - iconSize.x / 2, bubblePos.y + bubbleSize.y / 2 - iconSize.y / 2);
|
||||
drawList->AddText(Menu::Font::g_AwesomeFont, iconScale, iconPos, textColor, submenu->m_Icon.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
// Label below button
|
||||
ImVec2 labelSize = ImGui::CalcTextSize(submenu->m_Name.c_str());
|
||||
ImVec2 labelPos(center.x - labelSize.x / 2, bubblePos.y + bubbleSize.y + 6);
|
||||
drawList->AddText(labelPos, textColor, submenu->m_Name.c_str());
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (activeSubmenu)
|
||||
{
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(100, 40), ImVec2(io.DisplaySize.x * 0.9f, 200));
|
||||
if (ImGui::Begin("##CategorySelectorWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
activeSubmenu->DrawCategorySelectors();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (UIManager::ShowingContentWindow() && activeSubmenu)
|
||||
{
|
||||
ImVec2 defaultSize(*Pointers.ScreenResX / 2.8f, *Pointers.ScreenResY / 2.5f);
|
||||
ImGui::SetNextWindowSize(defaultSize, ImGuiCond_FirstUseEver);
|
||||
|
||||
if (ImGui::Begin("##OptionsContentWindow", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar))
|
||||
{
|
||||
ImFont* optionsFont = UIManager::GetOptionsFont();
|
||||
if (optionsFont)
|
||||
ImGui::PushFont(optionsFont);
|
||||
activeSubmenu->Draw();
|
||||
if (optionsFont)
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
#include "Themes.hpp"
|
||||
#include "core/commands/ColorCommand.hpp"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void DefaultStyle()
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
// Text
|
||||
style.Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
|
||||
// Backgrounds
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
|
||||
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
||||
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 0.95f);
|
||||
|
||||
// Borders
|
||||
style.Colors[ImGuiCol_Border] = ImVec4(0.28f, 0.28f, 0.28f, 0.25f);
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
|
||||
// Frames
|
||||
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.15f, 0.15f, 0.17f, 1.00f);
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.35f, 0.59f, 0.35f, 0.75f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.47f, 0.75f, 0.47f, 0.85f);
|
||||
|
||||
// Title bars
|
||||
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.06f, 0.06f, 0.07f, 1.00f);
|
||||
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.09f, 0.09f, 0.11f, 1.00f);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.04f, 0.04f, 0.05f, 1.00f);
|
||||
|
||||
// Menus/tabs
|
||||
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
||||
style.Colors[ImGuiCol_Tab] = ImVec4(0.30f, 0.55f, 0.30f, 0.85f);
|
||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.40f, 0.65f, 0.40f, 0.85f);
|
||||
style.Colors[ImGuiCol_TabActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.25f, 0.40f, 0.25f, 0.70f);
|
||||
style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.30f, 0.55f, 0.30f, 0.85f);
|
||||
|
||||
// Scrollbar
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.80f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
|
||||
// Checkmarks, sliders
|
||||
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.36f, 0.85f, 0.56f, 1.00f);
|
||||
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.35f, 0.59f, 0.35f, 1.00f);
|
||||
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
// Buttons
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.35f, 0.59f, 0.35f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.65f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
// Headers
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.30f, 0.50f, 0.30f, 1.00f);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.40f, 0.65f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
// Separators
|
||||
style.Colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 0.50f);
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.45f, 0.80f, 0.45f, 0.78f);
|
||||
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.55f, 0.90f, 0.55f, 1.00f);
|
||||
|
||||
// Resize grips
|
||||
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.50f, 0.50f, 0.50f, 0.30f);
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.60f, 0.85f, 0.60f, 0.60f);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.70f, 0.95f, 0.70f, 0.90f);
|
||||
|
||||
// Plots
|
||||
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.80f, 0.80f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.85f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.35f, 0.59f, 0.35f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
// Drag & drop
|
||||
style.Colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||
|
||||
// Navigation highlighting
|
||||
style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.40f, 0.90f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
||||
style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
|
||||
|
||||
// Modal/background dimming
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.10f, 0.10f, 0.10f, 0.35f);
|
||||
|
||||
// Rounding
|
||||
style.GrabRounding = style.FrameRounding = style.ChildRounding = style.WindowRounding = 8.0f;
|
||||
}
|
||||
|
||||
void SetupStyle()
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// Resolve path
|
||||
char* appDataPath = nullptr;
|
||||
size_t len = 0;
|
||||
_dupenv_s(&appDataPath, &len, "APPDATA");
|
||||
std::string settingsPath = std::string(appDataPath ? appDataPath : "") + "\\YimMenuV2\\GUISettings.json";
|
||||
free(appDataPath);
|
||||
|
||||
// Try loading colors from file
|
||||
if (std::filesystem::exists(settingsPath))
|
||||
{
|
||||
std::ifstream file(settingsPath);
|
||||
if (file.is_open())
|
||||
{
|
||||
nlohmann::json json;
|
||||
file >> json;
|
||||
file.close();
|
||||
|
||||
for (int i = 0; i < ImGuiCol_COUNT; ++i)
|
||||
{
|
||||
const char* name = ImGui::GetStyleColorName(i);
|
||||
auto it = json.find(name);
|
||||
if (it != json.end() && it->is_array() && it->size() == 4)
|
||||
{
|
||||
style.Colors[i] = ImVec4((*it)[0], (*it)[1], (*it)[2], (*it)[3]);
|
||||
}
|
||||
}
|
||||
return; // Done applying custom colors
|
||||
}
|
||||
}
|
||||
DefaultStyle();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <imgui.h>
|
||||
#include "core/frontend/manager/Category.hpp"
|
||||
#include "game/frontend/items/Items.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
// Forward declarations of each theme's render function, append when adding new themes
|
||||
extern void RenderClassicTheme();
|
||||
extern void RenderModernTheme();
|
||||
extern void RenderModernVTheme();
|
||||
extern void RenderModularTheme();
|
||||
extern void SetupStyle();
|
||||
extern void DefaultStyle();
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "game/frontend/ChatDisplay.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "types/pad/ControllerInputs.hpp"
|
||||
#include "core/frontend/manager/styles/Themes.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace YimMenu
|
||||
m_IsOpen(false)
|
||||
{
|
||||
Menu::SetupFonts();
|
||||
Menu::SetupStyle();
|
||||
SetupStyle();
|
||||
Menu::Init();
|
||||
|
||||
Renderer::AddWindowProcedureCallback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
#include "core/filemgr/FileMgr.hpp"
|
||||
#include "core/memory/ModuleMgr.hpp"
|
||||
#include "Onboarding.hpp"
|
||||
#include "core/frontend/manager/styles/Themes.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void Menu::Init()
|
||||
{
|
||||
SetupStyle();
|
||||
// Arguably the only place this file should be edited at for more menus
|
||||
UIManager::AddSubmenu(std::make_shared<Submenus::Self>());
|
||||
UIManager::AddSubmenu(std::make_shared<Submenus::Vehicle>());
|
||||
@@ -53,46 +55,6 @@ namespace YimMenu
|
||||
-1);
|
||||
}
|
||||
|
||||
void Menu::SetupStyle()
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
style.Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
|
||||
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.10f, 0.10f, 0.12f, 1.00f);
|
||||
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 0.95f);
|
||||
|
||||
style.Colors[ImGuiCol_Border] = ImVec4(0.28f, 0.28f, 0.28f, 0.25f);
|
||||
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.15f, 0.15f, 0.17f, 1.00f);
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.35f, 0.59f, 0.35f, 0.75f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.47f, 0.75f, 0.47f, 0.85f);
|
||||
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.35f, 0.59f, 0.35f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.65f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.06f, 0.06f, 0.07f, 1.00f);
|
||||
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.09f, 0.09f, 0.11f, 1.00f);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.04f, 0.04f, 0.05f, 1.00f);
|
||||
|
||||
style.Colors[ImGuiCol_Tab] = ImVec4(0.30f, 0.55f, 0.30f, 0.85f);
|
||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.40f, 0.65f, 0.40f, 0.85f);
|
||||
style.Colors[ImGuiCol_TabActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.30f, 0.50f, 0.30f, 1.00f);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.40f, 0.65f, 0.40f, 1.00f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.80f, 0.80f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.85f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.35f, 0.59f, 0.35f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.47f, 0.75f, 0.47f, 1.00f);
|
||||
|
||||
style.GrabRounding = style.FrameRounding = style.ChildRounding = style.WindowRounding = 8.0f;
|
||||
}
|
||||
|
||||
static const ImWchar* GetGlyphRangesCyrillicOnly()
|
||||
{
|
||||
static const ImWchar ranges[] =
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
namespace YimMenu::Menu
|
||||
{
|
||||
extern void Init();
|
||||
extern void SetupStyle();
|
||||
extern void SetupFonts();
|
||||
|
||||
namespace Font
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "game/frontend/items/Items.hpp"
|
||||
#include "game/frontend/items/DrawHotkey.hpp"
|
||||
#include "game/frontend/submenus/Settings/LuaScripts.hpp"
|
||||
#include "game/frontend/submenus/Settings/GUISettings.hpp"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
@@ -110,5 +111,6 @@ namespace YimMenu::Submenus
|
||||
AddCategory(std::move(gui));
|
||||
AddCategory(std::move(game));
|
||||
AddCategory(BuildLuaScriptsMenu());
|
||||
AddCategory(DrawGUISettingsMenu());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
#include "GUISettings.hpp"
|
||||
#include "core/commands/ColorCommand.hpp"
|
||||
#include "core/commands/Command.hpp"
|
||||
#include "core/commands/FloatCommand.hpp"
|
||||
#include "core/frontend/manager/styles/Themes.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <Windows.h>
|
||||
#include <regex>
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
static std::vector<std::unique_ptr<ColorCommand>> g_ColorCommands;
|
||||
static std::unordered_map<std::string, float> g_RoundingValues;
|
||||
static std::unordered_map<std::string, std::unique_ptr<FloatCommand>> g_FloatCommands; // Global map for all FloatCommands
|
||||
static bool g_ColorInit = false, g_RoundingInit = false;
|
||||
|
||||
static const std::string kSettingsFile = [] {
|
||||
char* path = nullptr;
|
||||
size_t len = 0;
|
||||
_dupenv_s(&path, &len, "APPDATA");
|
||||
std::string full = std::string(path ? path : "") + "\\YimMenuV2\\GUISettings.json";
|
||||
free(path);
|
||||
return full;
|
||||
}();
|
||||
|
||||
static std::string PrettyPrintLabel(const std::string& raw)
|
||||
{
|
||||
std::string out = raw;
|
||||
if (out.size() > 2 && out.compare(out.size() - 2, 2, "_X") == 0)
|
||||
out.replace(out.size() - 2, 2, " Horizontal");
|
||||
else if (out.size() > 2 && out.compare(out.size() - 2, 2, "_Y") == 0)
|
||||
out.replace(out.size() - 2, 2, " Vertical");
|
||||
|
||||
std::string spaced;
|
||||
spaced.reserve(out.size() + 10);
|
||||
for (size_t i = 0; i < out.size(); ++i)
|
||||
{
|
||||
if (i > 0 && isupper(out[i]) && islower(out[i - 1]))
|
||||
spaced += ' ';
|
||||
spaced += out[i];
|
||||
}
|
||||
|
||||
std::regex uscore_re("_");
|
||||
spaced = std::regex_replace(spaced, uscore_re, " ");
|
||||
|
||||
return spaced;
|
||||
}
|
||||
|
||||
void SyncColorCommandsToStyle()
|
||||
{
|
||||
auto& style = ImGui::GetStyle();
|
||||
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||
style.Colors[i] = g_ColorCommands[i]->GetState();
|
||||
}
|
||||
|
||||
static void SyncRoundingToStyle()
|
||||
{
|
||||
auto& s = ImGui::GetStyle();
|
||||
for (auto& [k, v] : g_RoundingValues)
|
||||
if (k == "WindowRounding")
|
||||
s.WindowRounding = v;
|
||||
else if (k == "FrameRounding")
|
||||
s.FrameRounding = v;
|
||||
else if (k == "GrabRounding")
|
||||
s.GrabRounding = v;
|
||||
else if (k == "ScrollbarRounding")
|
||||
s.ScrollbarRounding = v;
|
||||
else if (k == "ChildRounding")
|
||||
s.ChildRounding = v;
|
||||
else if (k == "PopupRounding")
|
||||
s.PopupRounding = v;
|
||||
else if (k == "TabRounding")
|
||||
s.TabRounding = v;
|
||||
}
|
||||
|
||||
static void LoadSettings()
|
||||
{
|
||||
if (!std::filesystem::exists(kSettingsFile))
|
||||
return;
|
||||
std::ifstream file(kSettingsFile);
|
||||
nlohmann::json json;
|
||||
file >> json;
|
||||
|
||||
// Load colors
|
||||
for (int i = 0; i < ImGuiCol_COUNT; ++i)
|
||||
if (auto it = json.find(ImGui::GetStyleColorName(i)); it != json.end() && it->is_array())
|
||||
g_ColorCommands[i]->SetState(ImVec4((*it)[0], (*it)[1], (*it)[2], (*it)[3]));
|
||||
|
||||
// Load rounding values
|
||||
for (const char* key : {"WindowRounding", "FrameRounding", "GrabRounding", "ScrollbarRounding", "ChildRounding", "PopupRounding", "TabRounding"})
|
||||
if (auto it = json.find(key); it != json.end())
|
||||
g_RoundingValues[key] = *it;
|
||||
|
||||
// Load all float command values (except colors and rounding, which are handled)
|
||||
for (auto& [key, cmd] : g_FloatCommands)
|
||||
{
|
||||
if (auto it = json.find(key); it != json.end() && it->is_number())
|
||||
{
|
||||
cmd->SetState(it->get<float>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveSettings()
|
||||
{
|
||||
nlohmann::json json;
|
||||
|
||||
// Save colors
|
||||
for (int i = 0; i < ImGuiCol_COUNT; ++i)
|
||||
{
|
||||
auto c = g_ColorCommands[i]->GetState();
|
||||
json[ImGui::GetStyleColorName(i)] = {c.x, c.y, c.z, c.w};
|
||||
}
|
||||
|
||||
// Save rounding
|
||||
for (auto& [k, v] : g_RoundingValues)
|
||||
json[k] = v;
|
||||
|
||||
// Save floats
|
||||
for (auto& [k, cmd] : g_FloatCommands)
|
||||
json[k] = cmd->GetState();
|
||||
|
||||
std::filesystem::create_directories(std::filesystem::path(kSettingsFile).parent_path());
|
||||
std::ofstream(kSettingsFile) << json.dump(4);
|
||||
}
|
||||
|
||||
void InitializeColorCommands()
|
||||
{
|
||||
if (g_ColorInit)
|
||||
return;
|
||||
auto& style = ImGui::GetStyle();
|
||||
for (int i = 0; i < ImGuiCol_COUNT; ++i)
|
||||
g_ColorCommands.emplace_back(std::make_unique<ColorCommand>(
|
||||
"ColorCommand." + std::string(ImGui::GetStyleColorName(i)),
|
||||
ImGui::GetStyleColorName(i),
|
||||
"Edit color for " + std::string(ImGui::GetStyleColorName(i)),
|
||||
style.Colors[i]));
|
||||
|
||||
if (!g_RoundingInit)
|
||||
{
|
||||
g_RoundingInit = true;
|
||||
g_RoundingValues = {
|
||||
{"WindowRounding", style.WindowRounding},
|
||||
{"FrameRounding", style.FrameRounding},
|
||||
{"GrabRounding", style.GrabRounding},
|
||||
{"ScrollbarRounding", style.ScrollbarRounding},
|
||||
{"ChildRounding", style.ChildRounding},
|
||||
{"PopupRounding", style.PopupRounding},
|
||||
{"TabRounding", style.TabRounding}};
|
||||
}
|
||||
|
||||
LoadSettings();
|
||||
SyncColorCommandsToStyle();
|
||||
SyncRoundingToStyle();
|
||||
g_ColorInit = true;
|
||||
}
|
||||
|
||||
static void DrawStyleVec2(const char* label, float& x, float& y, float min, float max)
|
||||
{
|
||||
std::string nameX = std::string(label) + "_X";
|
||||
std::string nameY = std::string(label) + "_Y";
|
||||
|
||||
// Use global float commands map
|
||||
if (!g_FloatCommands.count(nameX))
|
||||
g_FloatCommands[nameX] = std::make_unique<FloatCommand>(nameX.c_str(), nameX.c_str(), "Adjust " + nameX, min, max, x);
|
||||
if (!g_FloatCommands.count(nameY))
|
||||
g_FloatCommands[nameY] = std::make_unique<FloatCommand>(nameY.c_str(), nameY.c_str(), "Adjust " + nameY, min, max, y);
|
||||
|
||||
float newX = g_FloatCommands[nameX]->GetState();
|
||||
float newY = g_FloatCommands[nameY]->GetState();
|
||||
|
||||
bool changed = false;
|
||||
changed |= ImGui::SliderFloat(PrettyPrintLabel(nameX).c_str(), &newX, min, max, "%.1f");
|
||||
changed |= ImGui::SliderFloat(PrettyPrintLabel(nameY).c_str(), &newY, min, max, "%.1f");
|
||||
|
||||
if (changed)
|
||||
{
|
||||
g_FloatCommands[nameX]->SetState(newX);
|
||||
g_FloatCommands[nameY]->SetState(newY);
|
||||
x = newX;
|
||||
y = newY;
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawStyleFloat(const char* label, float& v, float min, float max)
|
||||
{
|
||||
std::string name(label);
|
||||
|
||||
if (!g_FloatCommands.count(name))
|
||||
g_FloatCommands[name] = std::make_unique<FloatCommand>(name.c_str(), name.c_str(), "Adjust " + name, min, max, v);
|
||||
|
||||
float newVal = g_FloatCommands[name]->GetState();
|
||||
if (ImGui::SliderFloat(PrettyPrintLabel(name).c_str(), &newVal, min, max, "%.1f"))
|
||||
{
|
||||
g_FloatCommands[name]->SetState(newVal);
|
||||
v = newVal;
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawColorsTab()
|
||||
{
|
||||
bool changed = false;
|
||||
ImGui::Text("Modify Colors:");
|
||||
ImGui::Separator();
|
||||
for (int i = 0; i < ImGuiCol_COUNT; ++i)
|
||||
{
|
||||
auto& cmd = g_ColorCommands[i];
|
||||
auto col = cmd->GetState();
|
||||
|
||||
if (ImGui::ColorEdit4(PrettyPrintLabel(ImGui::GetStyleColorName(i)).c_str(), (float*)&col))
|
||||
{
|
||||
cmd->SetState(col);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
SyncColorCommandsToStyle();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawRoundingTab()
|
||||
{
|
||||
bool changed = false;
|
||||
ImGui::Text("Adjust Rounding:");
|
||||
ImGui::Separator();
|
||||
for (auto& [k, v] : g_RoundingValues)
|
||||
if (ImGui::SliderFloat(PrettyPrintLabel(k).c_str(), &v, 0.0f, 20.0f, "%.1f"))
|
||||
changed = true;
|
||||
|
||||
if (changed)
|
||||
{
|
||||
SyncRoundingToStyle();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawLayoutTab()
|
||||
{
|
||||
auto& s = ImGui::GetStyle();
|
||||
ImGui::Text("Layout & Alignment:");
|
||||
ImGui::Separator();
|
||||
DrawStyleVec2("WindowPadding", s.WindowPadding.x, s.WindowPadding.y, 0.f, 32.f);
|
||||
DrawStyleVec2("ItemSpacing", s.ItemSpacing.x, s.ItemSpacing.y, 0.f, 32.f);
|
||||
DrawStyleVec2("ItemInnerSpacing", s.ItemInnerSpacing.x, s.ItemInnerSpacing.y, 0.f, 32.f);
|
||||
DrawStyleVec2("TouchExtraPadding", s.TouchExtraPadding.x, s.TouchExtraPadding.y, 0.f, 32.f);
|
||||
DrawStyleVec2("DisplaySafeAreaPadding", s.DisplaySafeAreaPadding.x, s.DisplaySafeAreaPadding.y, 0.f, 32.f);
|
||||
|
||||
DrawStyleFloat("IndentSpacing", s.IndentSpacing, 0.f, 64.f);
|
||||
DrawStyleFloat("ColumnsMinSpacing", s.ColumnsMinSpacing, 0.f, 64.f);
|
||||
|
||||
DrawStyleVec2("WindowTitleAlign", s.WindowTitleAlign.x, s.WindowTitleAlign.y, 0.f, 1.f);
|
||||
DrawStyleVec2("ButtonTextAlign", s.ButtonTextAlign.x, s.ButtonTextAlign.y, 0.f, 1.f);
|
||||
DrawStyleVec2("SelectableTextAlign", s.SelectableTextAlign.x, s.SelectableTextAlign.y, 0.f, 1.f);
|
||||
}
|
||||
|
||||
static void DrawBorderTab()
|
||||
{
|
||||
auto& s = ImGui::GetStyle();
|
||||
ImGui::Text("Border Sizes:");
|
||||
ImGui::Separator();
|
||||
DrawStyleFloat("WindowBorderSize", s.WindowBorderSize, 0.f, 8.f);
|
||||
DrawStyleFloat("FrameBorderSize", s.FrameBorderSize, 0.f, 8.f);
|
||||
DrawStyleFloat("TabBorderSize", s.TabBorderSize, 0.f, 8.f);
|
||||
DrawStyleFloat("PopupBorderSize", s.PopupBorderSize, 0.f, 8.f);
|
||||
}
|
||||
|
||||
static void DrawGlobalTab()
|
||||
{
|
||||
auto& s = ImGui::GetStyle();
|
||||
ImGui::Text("Global Settings:");
|
||||
ImGui::Separator();
|
||||
DrawStyleFloat("GlobalAlpha", s.Alpha, 0.1f, 1.f);
|
||||
DrawStyleFloat("DisabledAlpha", s.DisabledAlpha, 0.f, 1.f);
|
||||
DrawStyleFloat("MouseCursorScale", s.MouseCursorScale, 0.5f, 2.f);
|
||||
DrawStyleFloat("CurveTessellationTol", s.CurveTessellationTol, 0.1f, 10.f);
|
||||
}
|
||||
|
||||
static void DrawFontTab()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
static float scale = io.FontGlobalScale;
|
||||
ImGui::Text("Font Configuration:");
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Current Scale: %.2f", io.FontGlobalScale);
|
||||
ImGui::SliderFloat("Font Scale", &scale, 0.5f, 2.0f, "%.2f");
|
||||
if (ImGui::Button("Apply Font Scale"))
|
||||
io.FontGlobalScale = scale;
|
||||
}
|
||||
|
||||
std::shared_ptr<Category> DrawGUISettingsMenu()
|
||||
{
|
||||
InitializeColorCommands();
|
||||
auto imGuiCustomStyle = std::make_shared<Category>("Customize");
|
||||
imGuiCustomStyle->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
ImGui::Text("ImGui Style Editor");
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginTabBar("StyleTabs"))
|
||||
{
|
||||
if (ImGui::BeginTabItem("Colors"))
|
||||
{
|
||||
DrawColorsTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Rounding"))
|
||||
{
|
||||
DrawRoundingTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Layout"))
|
||||
{
|
||||
DrawLayoutTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Border"))
|
||||
{
|
||||
DrawBorderTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Global"))
|
||||
{
|
||||
DrawGlobalTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Fonts"))
|
||||
{
|
||||
DrawFontTab();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}));
|
||||
return imGuiCustomStyle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/frontend/manager/Category.hpp"
|
||||
#include "game/frontend/items/Items.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
std::shared_ptr<Category> DrawGUISettingsMenu();
|
||||
void InitializeColorCommands();
|
||||
void SyncColorCommandsToStyle();
|
||||
static void DrawStyleVec2(const char* label, float& x, float& y, float min, float max);
|
||||
static void DrawStyleFloat(const char* label, float& v, float min, float max);
|
||||
}
|
||||
Reference in New Issue
Block a user