[
  {
    "path": ".github/workflows/build.yml",
    "content": "on:\n  push:\n    branches:\n      - main\n\njobs:\n  build:\n    permissions:\n      id-token: write\n      contents: write\n    runs-on: windows-2022\n\n    steps:\n      - uses: actions/checkout@main\n\n      - uses: actions/checkout@master\n        with:\n          repository: microsoft/vcpkg\n          path: vcpkg\n\n      - name: Get short SHA\n        run: echo \"SHORT_SHA=$(\"${{ github.sha }}\".SubString(0, 8))\" >> $env:GITHUB_ENV\n\n      - uses: microsoft/setup-msbuild@v1.1\n\n      - run: .\\vcpkg\\bootstrap-vcpkg.bat\n      - run: .\\vcpkg\\vcpkg integrate install\n      - run: .\\vcpkg\\vcpkg install freetype:x86-windows-static\n      - run: .\\vcpkg\\vcpkg install cpr:x86-windows-static\n      - run: .\\vcpkg\\vcpkg install jsoncpp:x86-windows-static\n\n      - name: Build solution\n        run: msbuild KBotExt.sln /p:Platform=\"x86\" /p:Configuration=Release -m\n\n      - name: Upload build outputs\n        uses: actions/upload-artifact@v3\n        with:\n          name: KBotExt-${{ env.SHORT_SHA }}\n          path: Release/KBotExt.exe\n      \n      - name: Tag Repo\n        uses: richardsimko/update-tag@v1\n        with:\n          tag_name: prerelease\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n            \n\n      - name: Create Release\n        uses: ncipollo/release-action@v1.12.0\n        with:\n          artifacts: \"D:/a/KBotExt/KBotExt/Release/KBotExt.exe\"\n          token: ${{ secrets.GITHUB_TOKEN }}\n          tag: prerelease\n          name: KBotExt-${{ env.SHORT_SHA }}\n          allowUpdates: true\n          generateReleaseNotes: true\n          makeLatest: true\n          prerelease: true\n          updateOnlyUnreleased: true # Only update the latest release if it is not marked as released. Set it to true if needed.\n"
  },
  {
    "path": ".gitignore",
    "content": ".vs/\nx64/\nDebug/\nRelease/\nKBotExt/x64/\nKBotExt/Debug/\nKBotExt/Release/\nKBotExt/config.JSON\n"
  },
  {
    "path": "KBotExt/Auth.cpp",
    "content": "#include <Windows.h>\n#include <tlhelp32.h>\n#include <psapi.h>\n#include <string>\n#include <regex>\n#include <format>\n#pragma comment(lib, \"Version.lib\")\n\n#include \"Auth.h\"\n#include \"Utils.h\"\n\nClientInfo Auth::GetClientInfo(const DWORD& pid, bool riotClient)\n{\n\tif (!pid)\n\t\treturn {};\n\n\tconst std::string cmdLine = Utils::WstringToString(GetProcessCommandLine(pid));\n\tif (cmdLine.empty())\n\t\treturn {};\n\n\tClientInfo info;\n\tinfo.port = GetPort(cmdLine, riotClient);\n\tinfo.token = GetToken(cmdLine, riotClient);\n\tinfo.path = GetProcessPath(pid);\n\tinfo.version = GetFileVersion(info.path);\n\n\treturn info;\n}\n\nint Auth::GetPort(const std::string& cmdLine, const bool riotClient)\n{\n\tstd::regex regexStr;\n\tregexStr = riotClient ? \"--riotclient-app-port=(\\\\d*)\" : \"--app-port=(\\\\d*)\";\n\tif (std::smatch m; std::regex_search(cmdLine, m, regexStr))\n\t\treturn std::stoi(m[1].str());\n\n\treturn 0;\n}\n\nstd::string Auth::GetToken(const std::string& cmdLine, const bool riotClient)\n{\n\tstd::regex regexStr;\n\tregexStr = riotClient ? \"--riotclient-auth-token=([\\\\w-]*)\" : \"--remoting-auth-token=([\\\\w-]*)\";\n\tif (std::smatch m; std::regex_search(cmdLine, m, regexStr))\n\t{\n\t\tstd::string token = \"riot:\" + m[1].str();\n\t\tchar* tokenArray = token.data();\n\t\treturn base64.Encode(reinterpret_cast<unsigned char*>(tokenArray), static_cast<unsigned>(token.size()));\n\t}\n\n\treturn \"\";\n}\n\nstd::string Auth::MakeLeagueHeader(const ClientInfo& info)\n{\n\treturn \"Host: 127.0.0.1:\" + std::to_string(info.port) + \"\\r\\n\" +\n\t\t\"Connection: keep-alive\" + \"\\r\\n\" +\n\t\t\"Authorization: Basic \" + info.token + \"\\r\\n\" +\n\t\t\"Accept: application/json\" + \"\\r\\n\" +\n\t\t\"Content-Type: application/json\" + \"\\r\\n\" +\n\t\t\"Origin: https://127.0.0.1:\" + std::to_string(info.port) + \"\\r\\n\" +\n\t\t\"User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) LeagueOfLegendsClient/\" + info.version +\n\t\t\" (CEF 91) Safari/537.36\" + \"\\r\\n\" +\n\t\t\"X-Riot-Source: rcp-fe-lol-social\" + \"\\r\\n\" +\n\t\tR\"(sec-ch-ua: \"Chromium\";v=\"91\")\" + \"\\r\\n\" +\n\t\t\"sec-ch-ua-mobile: ?0\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Site: same-origin\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Mode: cors\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Dest: empty\" + \"\\r\\n\" +\n\t\t\"Referer: https://127.0.0.1:\" + std::to_string(info.port) + \"/index.html\" + \"\\r\\n\" +\n\t\t\"Accept-Encoding: gzip, deflate, br\" + \"\\r\\n\" +\n\t\t\"Accept-Language: en-US,en;q=0.9\\r\\n\\r\\n\";\n}\n\nstd::string Auth::MakeRiotHeader(const ClientInfo& info)\n{\n\treturn \"Host: 127.0.0.1:\" + std::to_string(info.port) + \"\\r\\n\" +\n\t\t\"Connection: keep-alive\" + \"\\r\\n\" +\n\t\t\"Authorization: Basic \" + info.token + \"\\r\\n\" +\n\t\t\"Accept: application/json\" + \"\\r\\n\" +\n\t\t\"Access-Control-Allow-Credentials: true\" + \"\\r\\n\" +\n\t\t\"Access-Control-Allow-Origin: 127.0.0.1\" + \"\\r\\n\" +\n\t\t\"Content-Type: application/json\" + \"\\r\\n\" +\n\t\t\"Origin: https://127.0.0.1:\" + std::to_string(info.port) + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Dest: empty\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Mode: cors\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-Site: same-origin\" + \"\\r\\n\" +\n\t\t\"Sec-Fetch-User: ?F\" + \"\\r\\n\" +\n\t\t\"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) RiotClient/\" + info.version +\n\t\t\" (CEF 74) Safari/537.36\" + \"\\r\\n\" +\n\t\t\"sec-ch-ua: Chromium\" + \"\\r\\n\" +\n\t\t\"Referer: https://127.0.0.1:\" + std::to_string(info.port) + \"/index.html\" + \"\\r\\n\" +\n\t\t\"Accept-Encoding: gzip, deflate, br\" + \"\\r\\n\" +\n\t\t\"Accept-Language: en-US,en;q=0.9\\r\\n\\r\\n\";\n}\n\nDWORD Auth::GetProcessId(const std::wstring& processName)\n{\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\tstatic auto pCreateToolhelp32Snapshot = (decltype(&CreateToolhelp32Snapshot))GetProcAddress(kernel32, \"CreateToolhelp32Snapshot\");\n\tstatic auto pProcess32FirstW = (decltype(&Process32FirstW))GetProcAddress(kernel32, \"Process32FirstW\");\n\tstatic auto pProcess32NextW = (decltype(&Process32NextW))GetProcAddress(kernel32, \"Process32NextW\");\n\n\tconst HANDLE snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);\n\tif (snapshot != INVALID_HANDLE_VALUE)\n\t{\n\t\tPROCESSENTRY32W entry;\n\t\tentry.dwSize = sizeof(PROCESSENTRY32W);\n\t\tif (pProcess32FirstW(snapshot, &entry))\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (std::wstring(entry.szExeFile) == processName)\n\t\t\t\t{\n\t\t\t\t\tCloseHandle(snapshot);\n\t\t\t\t\treturn entry.th32ProcessID;\n\t\t\t\t}\n\t\t\t} while (pProcess32NextW(snapshot, &entry));\n\t\t}\n\t}\n\tCloseHandle(snapshot);\n\treturn 0;\n}\n\nstd::vector<DWORD> Auth::GetAllProcessIds(const std::wstring& processName)\n{\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\tstatic auto pCreateToolhelp32Snapshot = (decltype(&CreateToolhelp32Snapshot))GetProcAddress(kernel32, \"CreateToolhelp32Snapshot\");\n\tstatic auto pProcess32FirstW = (decltype(&Process32FirstW))GetProcAddress(kernel32, \"Process32FirstW\");\n\tstatic auto pProcess32NextW = (decltype(&Process32NextW))GetProcAddress(kernel32, \"Process32NextW\");\n\n\tstd::vector<DWORD> pids;\n\tconst HANDLE snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);\n\tif (snapshot != INVALID_HANDLE_VALUE)\n\t{\n\t\tPROCESSENTRY32W entry;\n\t\tentry.dwSize = sizeof(PROCESSENTRY32W);\n\t\tif (pProcess32FirstW(snapshot, &entry))\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (std::wstring(entry.szExeFile) == processName)\n\t\t\t\t{\n\t\t\t\t\tpids.emplace_back(entry.th32ProcessID);\n\t\t\t\t}\n\t\t\t} while (pProcess32NextW(snapshot, &entry));\n\t\t}\n\t}\n\tCloseHandle(snapshot);\n\treturn pids;\n}\n\nstd::wstring Auth::GetProcessCommandLine(const DWORD& processId)\n{\n\tusing tNtQueryInformationProcess = NTSTATUS(__stdcall*)\n\t\t(\n\t\t\tHANDLE ProcessHandle,\n\t\t\tULONG ProcessInformationClass,\n\t\t\tPVOID ProcessInformation,\n\t\t\tULONG ProcessInformationLength,\n\t\t\tPULONG ReturnLength\n\t\t\t);\n\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\n\tstatic auto pOpenProcess = (decltype(&OpenProcess))GetProcAddress(kernel32, \"OpenProcess\");\n\tstd::wstring result;\n\tconst HANDLE processHandle = pOpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, processId);\n\n\tstatic auto pGetNativeSystemInfo = (decltype(&GetNativeSystemInfo))GetProcAddress(kernel32, \"GetNativeSystemInfo\");\n\tSYSTEM_INFO si;\n\tpGetNativeSystemInfo(&si);\n\n\tstatic auto pIsWow64Process = (decltype(&IsWow64Process))GetProcAddress(kernel32, \"IsWow64Process\");\n\tstatic auto pGetCurrentProcess = (decltype(&GetCurrentProcess))GetProcAddress(kernel32, \"GetCurrentProcess\");\n\tBOOL wow;\n\tpIsWow64Process(pGetCurrentProcess(), &wow);\n\n\tconst DWORD ProcessParametersOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x20 : 0x10;\n\tconst DWORD CommandLineOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x70 : 0x40;\n\n\tconst DWORD pebSize = ProcessParametersOffset + 8; // size until ProcessParameters\n\tconst auto peb = static_cast<PBYTE>(malloc(pebSize));\n\tZeroMemory(peb, pebSize);\n\n\tconst DWORD processParametersSize = CommandLineOffset + 16;\n\tconst auto processParameters = static_cast<PBYTE>(malloc(processParametersSize));\n\tZeroMemory(processParameters, processParametersSize);\n\n\tif (wow)\n\t{\n\t\tusing PROCESS_BASIC_INFORMATION_WOW64 = struct _PROCESS_BASIC_INFORMATION_WOW64\n\t\t{\n\t\t\tPVOID Reserved1[2];\n\t\t\tPVOID64 PebBaseAddress;\n\t\t\tPVOID Reserved2[4];\n\t\t\tULONG_PTR UniqueProcessId[2];\n\t\t\tPVOID Reserved3[2];\n\t\t};\n\n\t\tusing UNICODE_STRING_WOW64 = struct _UNICODE_STRING_WOW64\n\t\t{\n\t\t\tUSHORT Length;\n\t\t\tUSHORT MaximumLength;\n\t\t\tPVOID64 Buffer;\n\t\t};\n\n\t\tusing tNtWow64ReadVirtualMemory64 = NTSTATUS(NTAPI*)(\n\t\t\tIN HANDLE ProcessHandle,\n\t\t\tIN PVOID64 BaseAddress,\n\t\t\tOUT PVOID Buffer,\n\t\t\tIN ULONG64 Size,\n\t\t\tOUT PULONG64 NumberOfBytesRead);\n\n\t\tPROCESS_BASIC_INFORMATION_WOW64 pbi;\n\t\tZeroMemory(&pbi, sizeof(pbi));\n\n\t\tconst auto NtQueryInformationProcess =\n\t\t\treinterpret_cast<tNtQueryInformationProcess>(GetProcAddress(GetModuleHandleA(\"ntdll.dll\"), \"NtWow64QueryInformationProcess64\"));\n\t\tif (auto status = NtQueryInformationProcess(processHandle, 0, &pbi, sizeof(pbi), nullptr); status != 0)\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"NtWow64QueryInformationProcess64 failed, error code: {}\", status).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst auto NtWow64ReadVirtualMemory64 =\n\t\t\treinterpret_cast<tNtWow64ReadVirtualMemory64>(GetProcAddress(GetModuleHandleA(\"ntdll.dll\"), \"NtWow64ReadVirtualMemory64\"));\n\n\t\tif (auto status = NtWow64ReadVirtualMemory64(processHandle, pbi.PebBaseAddress, peb, pebSize, nullptr); status != 0)\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"PEB NtWow64ReadVirtualMemory64 failed, error code: {}\", status).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst auto parameters = *reinterpret_cast<PVOID64*>(peb + ProcessParametersOffset);\n\t\tif (auto status = NtWow64ReadVirtualMemory64(\n\t\t\tprocessHandle, parameters, processParameters, processParametersSize, nullptr); status != 0)\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"processParameters NtWow64ReadVirtualMemory64 failed, error code: {}\", status).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst UNICODE_STRING_WOW64* pCommandLine = reinterpret_cast<UNICODE_STRING_WOW64*>(processParameters + CommandLineOffset);\n\t\tconst auto commandLineCopy = static_cast<PWSTR>(malloc(pCommandLine->MaximumLength));\n\t\tif (auto status = NtWow64ReadVirtualMemory64(processHandle, pCommandLine->Buffer, commandLineCopy, pCommandLine->MaximumLength, nullptr);\n\t\t\tstatus != 0)\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"pCommandLine NtWow64ReadVirtualMemory64 failed, error code: {}\", status).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tresult = std::wstring(commandLineCopy);\n\t\tCloseHandle(processHandle);\n\t}\n\telse\n\t{\n\t\tusing PROCESS_BASIC_INFORMATION = struct _PROCESS_BASIC_INFORMATION\n\t\t{\n\t\t\tLONG ExitStatus;\n\t\t\tPVOID PebBaseAddress;\n\t\t\tULONG_PTR AffinityMask;\n\t\t\tLONG BasePriority;\n\t\t\tHANDLE UniqueProcessId;\n\t\t\tHANDLE InheritedFromUniqueProcessId;\n\t\t};\n\n\t\ttypedef struct _UNICODE_STRING\n\t\t{\n\t\t\tUSHORT Length;\n\t\t\tUSHORT MaximumLength;\n\t\t\tPWSTR Buffer;\n\t\t} UNICODE_STRING, * PUNICODE_STRING [[maybe_unused]];\n\t\t/*[[maybe_unused]]*/ using PCUNICODE_STRING = const UNICODE_STRING*;\n\n\t\tPROCESS_BASIC_INFORMATION pbi;\n\t\tZeroMemory(&pbi, sizeof(pbi));\n\n\t\tconst auto NtQueryInformationProcess =\n\t\t\treinterpret_cast<tNtQueryInformationProcess>(GetProcAddress(GetModuleHandleA(\"ntdll.dll\"), \"NtQueryInformationProcess\"));\n\t\tif (auto status = NtQueryInformationProcess(processHandle, 0, &pbi, sizeof(pbi), nullptr); status != 0)\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"NtQueryInformationProcess failed, error code: {}\", status).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tstatic auto pReadProcessMemory = (decltype(&ReadProcessMemory))GetProcAddress(kernel32, \"ReadProcessMemory\");\n\t\tif (!pReadProcessMemory(processHandle, pbi.PebBaseAddress, peb, pebSize, nullptr))\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"PEB ReadProcessMemory failed, error code: {}\", GetLastError()).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tif (const PBYTE* parameters = static_cast<PBYTE*>(*reinterpret_cast<LPVOID*>(peb + ProcessParametersOffset)); !pReadProcessMemory(\n\t\t\tprocessHandle, parameters, processParameters, processParametersSize, nullptr))\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"processParameters ReadProcessMemory failed, error code: {}\", GetLastError()).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst UNICODE_STRING* pCommandLine = reinterpret_cast<UNICODE_STRING*>(processParameters + CommandLineOffset);\n\t\tconst auto commandLineCopy = static_cast<PWSTR>(malloc(pCommandLine->MaximumLength));\n\t\tif (!pReadProcessMemory(processHandle, pCommandLine->Buffer, commandLineCopy, pCommandLine->MaximumLength, nullptr))\n\t\t{\n\t\t\tMessageBoxA(nullptr, std::format(\"pCommandLine ReadProcessMemory failed, error code: {}\", GetLastError()).c_str(), nullptr, 0);\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn {};\n\t\t}\n\n\t\tresult = std::wstring(commandLineCopy);\n\t\tCloseHandle(processHandle);\n\t}\n\n\treturn result;\n}\n\nstd::wstring Auth::GetProcessPath(const DWORD& processId)\n{\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\tstatic auto pOpenProcess = (decltype(&OpenProcess))GetProcAddress(kernel32, \"OpenProcess\");\n\n\tif (const HANDLE processHandle = pOpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, processId))\n\t{\n\t\tstatic auto pK32GetModuleFileNameExW = (decltype(&K32GetModuleFileNameExW))GetProcAddress(kernel32, \"K32GetModuleFileNameExW\");\n\t\tif (WCHAR result[MAX_PATH]; pK32GetModuleFileNameExW(processHandle, nullptr, result, MAX_PATH))\n\t\t{\n\t\t\tCloseHandle(processHandle);\n\t\t\treturn { result };\n\t\t}\n\t\tCloseHandle(processHandle);\n\t}\n\treturn L\"\";\n}\n\nstd::string Auth::GetFileVersion(const std::wstring& file)\n{\n\tif (const DWORD versionSize = GetFileVersionInfoSizeW(file.c_str(), nullptr))\n\t{\n\t\tstd::vector<unsigned char> versionInfo(versionSize);\n\n\t\tif (GetFileVersionInfoW(file.c_str(), 0, versionSize, versionInfo.data()))\n\t\t{\n\t\t\tVS_FIXEDFILEINFO* lpFfi = nullptr;\n\t\t\tUINT size = sizeof(VS_FIXEDFILEINFO);\n\t\t\tif (VerQueryValueW(versionInfo.data(), L\"\\\\\", reinterpret_cast<LPVOID*>(&lpFfi), &size))\n\t\t\t{\n\t\t\t\tconst DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;\n\t\t\t\tconst DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;\n\t\t\t\tstd::string result = std::format(\"{}.{}.{}.{}\",\n\t\t\t\t\tHIWORD(dwFileVersionMS), LOWORD(dwFileVersionMS),\n\t\t\t\t\tHIWORD(dwFileVersionLS), LOWORD(dwFileVersionLS));\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\";\n}"
  },
  {
    "path": "KBotExt/Auth.h",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n\n#include \"base64.h\"\n\nstruct ClientInfo\n{\n\tint port = 0;\n\tstd::string token;\n\tstd::string header;\n\tstd::string version;\n\tstd::wstring path;\n};\n\nclass Auth\n{\npublic:\n\tAuth() = default;\n\t~Auth() = default;\n\n\tstatic std::vector<DWORD> GetAllProcessIds(const std::wstring& processName);\n\n\t// set riotClient flag when you need Riot Client info but RiotClientUx.exe is closed\n\tstatic ClientInfo GetClientInfo(const DWORD& pid, bool riotClient = false);\n\tstatic DWORD GetProcessId(const std::wstring& processName);\n\n\tstatic std::string MakeLeagueHeader(const ClientInfo& info);\n\tstatic std::string MakeRiotHeader(const ClientInfo& info);\n\nprivate:\n\tstatic inline Base64 base64;\n\n\tstatic int GetPort(const std::string& cmdLine, bool riotClient = false);\n\tstatic std::string GetToken(const std::string& cmdLine, bool riotClient = false);\n\n\tstatic std::wstring GetProcessCommandLine(const DWORD& processId);\n\tstatic std::wstring GetProcessPath(const DWORD& processId);\n\tstatic std::string GetFileVersion(const std::wstring& file);\n};\n"
  },
  {
    "path": "KBotExt/ChampsTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"LCU.h\"\n\n#pragma warning (disable : 4996)\n\nclass ChampsTab\n{\npublic:\n\tstatic void Render()\n\t{\n\t\tstatic bool bOnOpen = true;\n\t\tstatic unsigned iChampsOwned = 0;\n\t\tstatic bool bSortOnOpen = false;\n\n\t\tif (ImGui::BeginTabItem(\"Champs\"))\n\t\t{\n\t\t\tImGui::Text(\"Sort by: \");\n\t\t\tImGui::SameLine();\n\n\t\t\tstatic int iSort = 0;\n\t\t\tstatic int iLastSort = -1;\n\t\t\tImGui::RadioButton(\"Alphabetically\", &iSort, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Purchase date\", &iSort, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Mastery points\", &iSort, 2);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"ID\", &iSort, 3);\n\n\t\t\tif (bOnOpen)\n\t\t\t{\n\t\t\t\tbOnOpen = false;\n\t\t\t\tbSortOnOpen = true;\n\t\t\t\tiChampsOwned = 0;\n\t\t\t\tchampsMinimal.clear();\n\t\t\t\tchampsMastery.clear();\n\n\t\t\t\tstatic Json::Value root;\n\t\t\t\tstatic Json::CharReaderBuilder builder;\n\t\t\t\tstatic const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tstatic JSONCPP_STRING err;\n\t\t\t\tstd::string getSession = LCU::Request(\"GET\", \"https://127.0.0.1/lol-login/v1/session\");\n\t\t\t\tif (reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tstd::string summId = root[\"summonerId\"].asString();\n\n\t\t\t\t\tstd::string getChampions = LCU::Request(\"GET\",\n\t\t\t\t\t\tstd::format(\"https://127.0.0.1/lol-champions/v1/inventories/{}/champions-minimal\",\n\t\t\t\t\t\t\tsummId));\n\n\t\t\t\t\tif (reader->parse(getChampions.c_str(), getChampions.c_str() + static_cast<int>(getChampions.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto& champObj : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tChampMinimal champ;\n\n\t\t\t\t\t\t\t\tchamp.active = champObj[\"active\"].asBool();\n\t\t\t\t\t\t\t\tchamp.alias = champObj[\"alias\"].asString();\n\t\t\t\t\t\t\t\tchamp.banVoPath = champObj[\"banVoPath\"].asString();\n\t\t\t\t\t\t\t\tchamp.baseLoadScreenPath = champObj[\"baseLoadScreenPath\"].asString();\n\t\t\t\t\t\t\t\tchamp.botEnabled = champObj[\"botEnabled\"].asBool();\n\t\t\t\t\t\t\t\tchamp.chooseVoPath = champObj[\"chooseVoPath\"].asString();\n\t\t\t\t\t\t\t\tchamp.freeToPlay = champObj[\"freeToPlay\"].asBool();\n\t\t\t\t\t\t\t\tchamp.id = champObj[\"id\"].asInt();\n\t\t\t\t\t\t\t\tchamp.name = champObj[\"name\"].asString();\n\t\t\t\t\t\t\t\tauto& ownershipObj = champObj[\"ownership\"];\n\t\t\t\t\t\t\t\tchamp.freeToPlayReward = ownershipObj[\"freeToPlayReward\"].asBool();\n\t\t\t\t\t\t\t\tchamp.owned = ownershipObj[\"owned\"].asInt();\n\t\t\t\t\t\t\t\tif (champ.owned)\n\t\t\t\t\t\t\t\t\tiChampsOwned++;\n\t\t\t\t\t\t\t\tif (champ.freeToPlay && !champ.owned)\n\t\t\t\t\t\t\t\t\tchamp.purchased = \"0\";\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tchamp.purchased = champObj[\"purchased\"].asString();\n\t\t\t\t\t\t\t\tchamp.rankedPlayEnabled = champObj[\"rankedPlayEnabled\"].asBool();\n\t\t\t\t\t\t\t\t//auto rolesObj = champObj.GetObject(\"roles\"); // TODO\n\t\t\t\t\t\t\t\tchamp.squarePortraitPath = champObj[\"squarePortraitPath\"].asString();\n\t\t\t\t\t\t\t\tchamp.stingerSfxPath = champObj[\"stingerSfxPath\"].asString();\n\t\t\t\t\t\t\t\tchamp.title = champObj[\"title\"].asString();\n\n\t\t\t\t\t\t\t\tchampsMinimal.emplace_back(champ);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::string getCollections = LCU::Request(\"GET\",\n\t\t\t\t\t\tstd::format(\"https://127.0.0.1/lol-collections/v1/inventories/{}/champion-mastery\",\n\t\t\t\t\t\t\tsummId));\n\n\t\t\t\t\tif (reader->parse(getCollections.c_str(), getCollections.c_str() + static_cast<int>(getCollections.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto& champObj : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tChampMastery champ;\n\t\t\t\t\t\t\t\tchamp.championId = champObj[\"championId\"].asInt();\n\t\t\t\t\t\t\t\tchamp.championLevel = champObj[\"championLevel\"].asInt();\n\t\t\t\t\t\t\t\tchamp.championPoints = champObj[\"championPoints\"].asInt();\n\t\t\t\t\t\t\t\tchamp.championPointsSinceLastLevel = champObj[\"championPointsSinceLastLevel\"].asInt();\n\t\t\t\t\t\t\t\tchamp.championPointsUntilNextLevel = champObj[\"championPointsUntilNextLevel\"].asInt();\n\t\t\t\t\t\t\t\tchamp.chestGranted = champObj[\"chestGranted\"].asInt();\n\t\t\t\t\t\t\t\tchamp.formattedChampionPoints = champObj[\"formattedChampionPoints\"].asString();\n\t\t\t\t\t\t\t\tchamp.formattedMasteryGoal = champObj[\"formattedMasteryGoal\"].asString();\n\t\t\t\t\t\t\t\tchamp.highestGrade = champObj[\"highestGrade\"].asString();\n\t\t\t\t\t\t\t\tchamp.lastPlayTime = std::to_string(champObj[\"lastPlayTime\"].asUInt64());\n\t\t\t\t\t\t\t\tchamp.playerId = std::to_string(champObj[\"playerId\"].asInt64());\n\t\t\t\t\t\t\t\tchamp.tokensEarned = champObj[\"tokensEarned\"].asInt();\n\n\t\t\t\t\t\t\t\tchampsMastery.emplace_back(champ);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tchampsAll.clear();\n\n\t\t\t\tfor (const auto& minimal : champsMinimal)\n\t\t\t\t{\n\t\t\t\t\tif (!minimal.owned)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tChampAll champ;\n\t\t\t\t\tchamp.min = minimal;\n\t\t\t\t\tfor (const auto& mastery : champsMastery)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (minimal.id == mastery.championId)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchamp.mas = mastery;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tchampsAll.emplace_back(champ);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((iLastSort != iSort) || bSortOnOpen)\n\t\t\t{\n\t\t\t\tbSortOnOpen = false;\n\t\t\t\tiLastSort = iSort;\n\t\t\t\tswitch (iSort)\n\t\t\t\t{\n\t\t\t\t\t// alphabetically\n\t\t\t\tcase 0:\n\t\t\t\t\tstd::ranges::sort(champsAll, [](const ChampAll& lhs, const ChampAll& rhs) {\n\t\t\t\t\t\treturn lhs.min.name < rhs.min.name;\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t\t// purchase date\n\t\t\t\tcase 1:\n\t\t\t\t\tstd::ranges::sort(champsAll, [](const ChampAll& lhs, const ChampAll& rhs) {\n\t\t\t\t\t\treturn std::stoll(lhs.min.purchased) < std::stoll(rhs.min.purchased);\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t\t// mastery points\n\t\t\t\tcase 2:\n\t\t\t\t\tstd::ranges::sort(champsAll, [](const ChampAll& lhs, const ChampAll& rhs) {\n\t\t\t\t\t\treturn lhs.mas.championPoints > rhs.mas.championPoints;\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t\t// id\n\t\t\t\tcase 3:\n\t\t\t\t\tstd::ranges::sort(champsAll, [](const ChampAll& lhs, const ChampAll& rhs) {\n\t\t\t\t\t\treturn lhs.min.id < rhs.min.id;\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tstatic char allNamesSeparator[64] = \",\";\n\t\t\tif (ImGui::Button(\"Copy names to clipboard##champsTab\"))\n\t\t\t{\n\t\t\t\tstd::string allNames;\n\t\t\t\tfor (const auto& [min, mas] : champsAll)\n\t\t\t\t{\n\t\t\t\t\tif (!min.owned)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tallNames += min.name + allNamesSeparator;\n\t\t\t\t}\n\t\t\t\tUtils::CopyToClipboard(allNames);\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\tconst ImVec2 label_size = ImGui::CalcTextSize(\"W\", nullptr, true);\n\t\t\tImGui::InputTextMultiline(\"##separatorChampsTab\", allNamesSeparator, IM_ARRAYSIZE(allNamesSeparator),\n\t\t\t\tImVec2(0, label_size.y + ImGui::GetStyle().FramePadding.y * 2.0f), ImGuiInputTextFlags_AllowTabInput);\n\n\t\t\tImGui::Separator();\n\t\t\tImGui::Text(\"Champions owned: %d\", iChampsOwned);\n\t\t\tfor (const auto& [min, mas] : champsAll)\n\t\t\t{\n\t\t\t\tif (!min.owned)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tint64_t t = std::stoll(min.purchased);\n\t\t\t\tt /= 1000;\n\t\t\t\tchar buffer[50];\n\t\t\t\tstrftime(buffer, 100, \"%Y-%m-%d %H:%M:%S\", localtime(&t));\n\n\t\t\t\tstd::string inputId = \"champInput\";\n\t\t\t\tinputId.append(std::to_string(min.id));\n\t\t\t\tchar input[768];\n\n\t\t\t\tfloat textHeight = (label_size.y + ImGui::GetStyle().FramePadding.y) * 3.f;\n\t\t\t\tstd::string text = std::format(R\"(name: {}\npurchased: {}\nid: {})\", min.name, buffer, min.id);\n\n\t\t\t\tif (!mas.lastPlayTime.empty())\n\t\t\t\t{\n\t\t\t\t\ttextHeight = (label_size.y + ImGui::GetStyle().FramePadding.y) * 12.f;\n\n\t\t\t\t\tt = std::stoll(mas.lastPlayTime);\n\t\t\t\t\tt /= 1000;\n\t\t\t\t\tstrftime(buffer, 100, \"%Y-%m-%d %H:%M:%S\", localtime(&t));\n\n\t\t\t\t\ttext += std::format(R\"(\nchampionLevel: {}\nchampionPoints: {}\nchampionPointsSinceLastLevel: {}\nchampionPointsUntilNextLevel: {}\nchestGranted: {}\nformattedChampionPoints: {}\nformattedMasteryGoal: {}\nhighestGrade: {}\nlastPlayTime: {}\nplayerId: {}\ntokensEarned: {})\", mas.championLevel, mas.championPoints, mas.championPointsSinceLastLevel,\nmas.championPointsUntilNextLevel, mas.chestGranted, mas.formattedChampionPoints, mas.formattedMasteryGoal,\nmas.highestGrade, buffer, mas.playerId, mas.tokensEarned);\n\t\t\t\t}\n\n\t\t\t\tstrcpy(input, text.c_str());\n\t\t\t\tImGui::PushID(inputId.c_str());\n\t\t\t\tImGui::InputTextMultiline(\"\", input, IM_ARRAYSIZE(input), ImVec2(ImGui::GetWindowSize().x, textHeight),\n\t\t\t\t\tImGuiInputTextFlags_ReadOnly);\n\t\t\t\tImGui::PopID();\n\t\t\t}\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t\tbOnOpen = true;\n\t}\n};\n"
  },
  {
    "path": "KBotExt/Config.h",
    "content": "#pragma once\n\n#include <string>\n#include <fstream>\n#include <filesystem>\n#include <vector>\n\n#include \"Includes.h\"\n\nstruct Settings\n{\n\tSettings() : hwnd(nullptr)\n\t{\n\t}\n\n\tHWND hwnd;\n\tstd::string fileName = \"\";\n\tconst std::string settingsFile = \"config.JSON\";\n\tstd::string currentDebugger; // debugger path\n\tstd::vector<std::string> ignoredVersions;\n\n\tbool autoRename = false;\n\tstd::string leaguePath = \"C:/Riot Games/League of Legends/\";\n\tfloat fontScale = 1.f;\n\tbool streamProof = false;\n\tbool debugger = false;\n\tbool noAdmin = false;\n\tbool checkPrerelease = false;\n\n\tstruct\n\t{\n\t\tint width = 730;\n\t\tint height = 530;\n\t} Window;\n\n\tstruct\n\t{\n\t\tstd::string playerName;\n\t} infoTab;\n\n\tstruct\n\t{\n\t\tstd::string method;\n\t\tstd::string urlText;\n\t\tstd::string requestText;\n\t\tstd::string port;\n\t\tstd::string header;\n\t} customTab;\n\n\tstruct\n\t{\n\t\tstd::string destination;\n\t\tstd::string method;\n\t\tstd::string args;\n\t} invokeTab;\n\n\tstruct\n\t{\n\t\tstd::string language = \"en_US\";\n\t\tstd::string leagueArgs = \"--locale=en_US\";\n\t} loginTab;\n\n\tstruct\n\t{\n\t\tsize_t indexFirstRole = 0;\n\t\tsize_t indexSecondRole = 0;\n\t\tsize_t indexMultiSearch = 0;\n\t\tbool autoAcceptEnabled = false;\n\t\tbool instalockEnabled = false;\n\t\tbool autoBanEnabled = false;\n\t\tint instalockId = 0;\n\t\tint instalockDelay = 0;\n\t\tstd::string instantMessage;\n\t\tint instantMessageDelay = 0;\n\t\tint instantMessageTimes = 1;\n\t\tint instantMessageDelayTimes = 0;\n\t\tint autoBanId = 0;\n\t\tint autoBanDelay = 0;\n\t\tbool dodgeOnBan = false;\n\t\tint backupId = 0;\n\t\tbool instantMute = false;\n\t\tbool sideNotification = false;\n\t} gameTab;\n};\n\nextern Settings S;\n\nclass Config\n{\npublic:\n\tstatic void Save()\n\t{\n\t\t// if file doesn't exist, create new one with {} so it can be parsed\n\t\tif (!std::filesystem::exists(S.settingsFile))\n\t\t{\n\t\t\tstd::ofstream file(S.settingsFile);\n\t\t\tfile << \"{}\";\n\t\t\tfile.close();\n\t\t}\n\n\t\tJson::Value root;\n\t\tJSONCPP_STRING err;\n\n\t\tstd::ifstream iFile(S.settingsFile);\n\n\t\tif (iFile.good())\n\t\t{\n\t\t\tif (Json::CharReaderBuilder builder; parseFromStream(builder, iFile, &root, &err))\n\t\t\t{\n\t\t\t\troot[\"autoRename\"] = S.autoRename;\n\t\t\t\troot[\"leaguePath\"] = S.leaguePath;\n\t\t\t\troot[\"debugger\"] = S.debugger;\n\t\t\t\troot[\"window\"][\"width\"] = S.Window.width;\n\t\t\t\troot[\"window\"][\"height\"] = S.Window.height;\n\t\t\t\troot[\"fontScale\"] = S.fontScale;\n\t\t\t\troot[\"loginTab\"][\"language\"] = S.loginTab.language;\n\t\t\t\troot[\"loginTab\"][\"leagueArgs\"] = S.loginTab.leagueArgs;\n\t\t\t\troot[\"streamProof\"] = S.streamProof;\n\t\t\t\troot[\"noAdmin\"] = S.noAdmin;\n\t\t\t\troot[\"checkPrerelease\"] = S.checkPrerelease;\n\n\t\t\t\troot[\"infoTab\"][\"playerName\"] = S.infoTab.playerName;\n\n\t\t\t\troot[\"customTab\"][\"method\"] = S.customTab.method;\n\t\t\t\troot[\"customTab\"][\"urlText\"] = S.customTab.urlText;\n\t\t\t\troot[\"customTab\"][\"requestText\"] = S.customTab.requestText;\n\t\t\t\troot[\"customTab\"][\"port\"] = S.customTab.port;\n\t\t\t\troot[\"customTab\"][\"header\"] = S.customTab.header;\n\t\t\t\troot[\"invokeTab\"][\"destination\"] = S.invokeTab.destination;\n\t\t\t\troot[\"invokeTab\"][\"method\"] = S.invokeTab.method;\n\t\t\t\troot[\"invokeTab\"][\"args\"] = S.invokeTab.args;\n\n\t\t\t\troot[\"gameTab\"][\"indexFirstRole\"] = S.gameTab.indexFirstRole;\n\t\t\t\troot[\"gameTab\"][\"indexSecondRole\"] = S.gameTab.indexSecondRole;\n\t\t\t\troot[\"gameTab\"][\"indexMultiSearch\"] = S.gameTab.indexMultiSearch;\n\t\t\t\troot[\"gameTab\"][\"autoAcceptEnabled\"] = S.gameTab.autoAcceptEnabled;\n\t\t\t\troot[\"gameTab\"][\"instalockEnabled\"] = S.gameTab.instalockEnabled;\n\t\t\t\troot[\"gameTab\"][\"autoBanEnabled\"] = S.gameTab.autoBanEnabled;\n\t\t\t\troot[\"gameTab\"][\"instalockDelay\"] = S.gameTab.instalockDelay;\n\t\t\t\troot[\"gameTab\"][\"instalockId\"] = S.gameTab.instalockId;\n\t\t\t\troot[\"gameTab\"][\"instantMessage\"] = S.gameTab.instantMessage;\n\t\t\t\troot[\"gameTab\"][\"instantMessageDelay\"] = S.gameTab.instantMessageDelay;\n\t\t\t\troot[\"gameTab\"][\"instantMessageTimes\"] = S.gameTab.instantMessageTimes;\n\t\t\t\troot[\"gameTab\"][\"instantMessageDelayTimes\"] = S.gameTab.instantMessageDelayTimes;\n\t\t\t\troot[\"gameTab\"][\"autoBanId\"] = S.gameTab.autoBanId;\n\t\t\t\troot[\"gameTab\"][\"autoBanDelay\"] = S.gameTab.autoBanDelay;\n\t\t\t\troot[\"gameTab\"][\"dodgeOnBan\"] = S.gameTab.dodgeOnBan;\n\t\t\t\troot[\"gameTab\"][\"backupId\"] = S.gameTab.backupId;\n\t\t\t\troot[\"gameTab\"][\"instantMute\"] = S.gameTab.instantMute;\n\t\t\t\troot[\"gameTab\"][\"sideNotification\"] = S.gameTab.sideNotification;\n\n\t\t\t\t{\n\t\t\t\t\troot[\"ignoredVersions\"] = Json::Value(Json::arrayValue);\n\t\t\t\t\tfor (const std::string& version : S.ignoredVersions)\n\t\t\t\t\t\troot[\"ignoredVersions\"].append(version);\n\t\t\t\t}\n\n\t\t\t\tif (!root.toStyledString().empty())\n\t\t\t\t{\n\t\t\t\t\tstd::ofstream oFile(S.settingsFile);\n\t\t\t\t\toFile << root.toStyledString() << std::endl;\n\t\t\t\t\toFile.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tiFile.close();\n\t}\n\n\tstatic void Load()\n\t{\n\t\tstd::fstream file(S.settingsFile, std::ios_base::in);\n\t\tif (file.good())\n\t\t{\n\t\t\tJson::Value root;\n\t\t\tJSONCPP_STRING err;\n\n\t\t\tif (Json::CharReaderBuilder builder; parseFromStream(builder, file, &root, &err))\n\t\t\t{\n\t\t\t\tif (auto t = root[\"autoRename\"]; !t.empty())\n\t\t\t\t\tS.autoRename = t.asBool();\n\t\t\t\tif (auto t = root[\"leaguePath\"]; !t.empty())\n\t\t\t\t\tS.leaguePath = t.asString();\n\t\t\t\tif (auto t = root[\"debugger\"]; !t.empty())\n\t\t\t\t\tS.debugger = t.asBool();\n\t\t\t\tif (auto t = root[\"window\"][\"width\"]; !t.empty())\n\t\t\t\t\tS.Window.width = t.asInt();\n\t\t\t\tif (auto t = root[\"window\"][\"height\"]; !t.empty())\n\t\t\t\t\tS.Window.height = t.asInt();\n\t\t\t\tif (auto t = root[\"fontScale\"]; !t.empty())\n\t\t\t\t\tS.fontScale = t.asFloat();\n\t\t\t\tif (auto t = root[\"loginTab\"][\"language\"]; !t.empty())\n\t\t\t\t\tS.loginTab.language = t.asString();\n\t\t\t\tif (auto t = root[\"loginTab\"][\"leagueArgs\"]; !t.empty())\n\t\t\t\t\tS.loginTab.leagueArgs = t.asString();\n\t\t\t\tif (auto t = root[\"streamProof\"]; !t.empty())\n\t\t\t\t\tS.streamProof = t.asBool();\n\t\t\t\tif (auto t = root[\"noAdmin\"]; !t.empty())\n\t\t\t\t\tS.noAdmin = t.asBool();\n\t\t\t\tif (auto t = root[\"checkPrerelease\"]; !t.empty())\n\t\t\t\t\tS.checkPrerelease = t.asBool();\n\n\t\t\t\tif (auto t = root[\"infoTab\"][\"playerName\"]; !t.empty())\n\t\t\t\t\tS.infoTab.playerName = t.asString();\n\n\t\t\t\tif (auto t = root[\"customTab\"][\"method\"]; !t.empty())\n\t\t\t\t\tS.customTab.method = t.asString();\n\t\t\t\tif (auto t = root[\"customTab\"][\"urlText\"]; !t.empty())\n\t\t\t\t\tS.customTab.urlText = t.asString();\n\t\t\t\tif (auto t = root[\"customTab\"][\"requestText\"]; !t.empty())\n\t\t\t\t\tS.customTab.requestText = t.asString();\n\t\t\t\tif (auto t = root[\"customTab\"][\"port\"]; !t.empty())\n\t\t\t\t\tS.customTab.port = t.asString();\n\t\t\t\tif (auto t = root[\"customTab\"][\"header\"]; !t.empty())\n\t\t\t\t\tS.customTab.header = t.asString();\n\n\t\t\t\tif (auto t = root[\"invokeTab\"][\"destination\"]; !t.empty())\n\t\t\t\t\tS.invokeTab.destination = t.asString();\n\t\t\t\tif (auto t = root[\"invokeTab\"][\"method\"]; !t.empty())\n\t\t\t\t\tS.invokeTab.method = t.asString();\n\t\t\t\tif (auto t = root[\"invokeTab\"][\"args\"]; !t.empty())\n\t\t\t\t\tS.invokeTab.args = t.asString();\n\n\t\t\t\tif (auto t = root[\"gameTab\"][\"indexFirstRole\"]; !t.empty())\n\t\t\t\t\tS.gameTab.indexFirstRole = t.asUInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"indexSecondRole\"]; !t.empty())\n\t\t\t\t\tS.gameTab.indexSecondRole = t.asUInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"indexMultiSearch\"]; !t.empty())\n\t\t\t\t\tS.gameTab.indexMultiSearch = t.asUInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"autoAcceptEnabled\"]; !t.empty())\n\t\t\t\t\tS.gameTab.autoAcceptEnabled = t.asBool();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instalockEnabled\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instalockEnabled = t.asBool();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"autoBanEnabled\"]; !t.empty())\n\t\t\t\t\tS.gameTab.autoBanEnabled = t.asBool();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instalockDelay\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instalockDelay = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instalockId\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instalockId = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instantMessage\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instantMessage = t.asString();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instantMessageDelay\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instantMessageDelay = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instantMessageTimes\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instantMessageTimes = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instantMessageDelayTimes\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instantMessageDelayTimes = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"autoBanId\"]; !t.empty())\n\t\t\t\t\tS.gameTab.autoBanId = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"autoBanDelay\"]; !t.empty())\n\t\t\t\t\tS.gameTab.autoBanDelay = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"dodgeOnBan\"]; !t.empty())\n\t\t\t\t\tS.gameTab.dodgeOnBan = t.asBool();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"backupId\"]; !t.empty())\n\t\t\t\t\tS.gameTab.backupId = t.asInt();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"instantMute\"]; !t.empty())\n\t\t\t\t\tS.gameTab.instantMute = t.asBool();\n\t\t\t\tif (auto t = root[\"gameTab\"][\"sideNotification\"]; !t.empty())\n\t\t\t\t\tS.gameTab.sideNotification = t.asBool();\n\n\t\t\t\tif (root[\"ignoredVersions\"].isArray() && !root[\"ignoredVersions\"].empty())\n\t\t\t\t{\n\t\t\t\t\tfor (const auto& i : root[\"ignoredVersions\"])\n\t\t\t\t\t{\n\t\t\t\t\t\tS.ignoredVersions.emplace_back(i.asString());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfile.close();\n\t}\n};\n"
  },
  {
    "path": "KBotExt/CustomTab.h",
    "content": "#pragma once\n\n#include \"Includes.h\"\n#include \"LCU.h\"\n\nclass CustomTab\n{\npublic:\n\tstatic void Custom()\n\t{\n\t\tstatic bool once = true;\n\n\t\tstatic char method[50];\n\t\tstatic char urlText[1024 * 16];\n\t\tstatic char requestText[1024 * 32];\n\n\t\tstatic char inputPort[64] = \"\";\n\t\tstatic char inputHeader[1024 * 16];\n\n\t\tstatic std::string customHeader = LCU::league.header;\n\t\tstatic int customPort = LCU::league.port;\n\n\t\tstatic bool isCustomOpen = false;\n\n\t\tstatic std::string ledgeUrl;\n\t\tstatic std::string storeUrl;\n\t\tstatic std::string localhostUrl = \"https://127.0.0.1\";\n\n\t\tif (once)\n\t\t{\n\t\t\tonce = false;\n\t\t\tstd::ranges::copy(S.customTab.method, method);\n\t\t\tstd::ranges::copy(S.customTab.urlText, urlText);\n\t\t\tstd::ranges::copy(S.customTab.requestText, requestText);\n\t\t\tstd::ranges::copy(S.customTab.port, inputPort);\n\t\t\tstd::ranges::copy(S.customTab.header, inputHeader);\n\t\t}\n\n\t\tif (onOpen)\n\t\t{\n\t\t\tcustomHeader = LCU::league.header;\n\t\t\tcustomPort = LCU::league.port;\n\n\t\t\tledgeUrl = GetLedgeUrl();\n\t\t\tstoreUrl = LCU::Request(\"GET\", \"/lol-store/v1/getStoreUrl\");\n\t\t\tstd::erase(storeUrl, '\"');\n\t\t}\n\n\t\tImGui::Text(\"Method:\");\n\t\tconst ImVec2 label_size = ImGui::CalcTextSize(\"W\", nullptr, true);\n\t\tImGui::InputTextEx(\"##inputMethod\", nullptr, method, IM_ARRAYSIZE(method),\n\t\t\tImVec2(S.Window.width - 130.f, label_size.y + ImGui::GetStyle().FramePadding.y * 2.0f), 0, nullptr, nullptr);\n\n\t\tImGui::Text(\"URL:\");\n\t\tImGui::InputTextMultiline(\"##inputUrl\", urlText, IM_ARRAYSIZE(urlText),\n\t\t\tImVec2(S.Window.width - 130.f, label_size.y + ImGui::GetStyle().FramePadding.y * 2.0f));\n\n\t\tImGui::Text(\"Body:\");\n\t\tImGui::InputTextMultiline(\"##inputBody\", (requestText), IM_ARRAYSIZE(requestText), ImVec2(S.Window.width - 130.f,\n\t\t\t(label_size.y + ImGui::GetStyle().FramePadding.y) *\n\t\t\t6.f), ImGuiInputTextFlags_AllowTabInput);\n\n\t\tS.customTab.method = method;\n\t\tS.customTab.urlText = urlText;\n\t\tS.customTab.requestText = requestText;\n\n\t\tif (ImGui::CollapsingHeader(\"Custom Port/Header\"))\n\t\t{\n\t\t\tisCustomOpen = true;\n\t\t\tImGui::Text(\"Port:\");\n\t\t\tImGui::InputText(\"##inputPort\", inputPort, 64, ImGuiInputTextFlags_CharsDecimal);\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"LCU\"))\n\t\t\t{\n\t\t\t\tif (strlen(urlText) == 0 || strcmp(urlText, localhostUrl.c_str()) == 0\n\t\t\t\t\t|| strcmp(urlText, storeUrl.c_str()) == 0 || strcmp(urlText, ledgeUrl.c_str()) == 0)\n\t\t\t\t{\n\t\t\t\t\tstd::strcpy(urlText, localhostUrl.c_str());\n\t\t\t\t}\n\t\t\t\tstd::strcpy(inputPort, std::to_string(LCU::league.port).c_str());\n\t\t\t\tstd::strcpy(inputHeader, LCU::league.header.c_str());\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Riot\"))\n\t\t\t{\n\t\t\t\tLCU::SetCurrentClientRiotInfo();\n\t\t\t\tif (strlen(urlText) == 0 || strcmp(urlText, localhostUrl.c_str()) == 0\n\t\t\t\t\t|| strcmp(urlText, storeUrl.c_str()) == 0 || strcmp(urlText, ledgeUrl.c_str()) == 0)\n\t\t\t\t{\n\t\t\t\t\tstd::strcpy(urlText, localhostUrl.c_str());\n\t\t\t\t}\n\t\t\t\tstd::strcpy(inputPort, std::to_string(LCU::riot.port).c_str());\n\t\t\t\tstd::strcpy(inputHeader, LCU::riot.header.c_str());\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\t/** \\\n\t\t\t* \\deprecated Use strcpy_s?\n\t\t\t*/\n\n\t\t\tif (ImGui::Button(\"Store\"))\n\t\t\t{\n\t\t\t\tstd::string storeHeader = LCU::GetStoreHeader();\n\t\t\t\tif (!storeHeader.empty())\n\t\t\t\t{\n\t\t\t\t\tif (strlen(method) != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::strcpy(method, Utils::ToUpper(std::string(method)).c_str());\n\t\t\t\t\t}\n\t\t\t\t\tif (strlen(urlText) == 0 || strcmp(urlText, localhostUrl.c_str()) == 0\n\t\t\t\t\t\t|| strcmp(urlText, storeUrl.c_str()) == 0 || strcmp(urlText, ledgeUrl.c_str()) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstoreUrl = LCU::Request(\"GET\", \"/lol-store/v1/getStoreUrl\");\n\t\t\t\t\t\tstd::erase(storeUrl, '\"');\n\t\t\t\t\t\tstd::strcpy(urlText, storeUrl.c_str());\n\t\t\t\t\t}\n\t\t\t\t\tstd::strcpy(inputPort, \"443\");\n\t\t\t\t\tstd::strcpy(inputHeader, storeHeader.c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Ledge\"))\n\t\t\t{\n\t\t\t\tstd::string ledgeHeader;\n\n\t\t\t\tledgeUrl = GetLedgeUrl();\n\t\t\t\tif (!ledgeUrl.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string ledgeHost;\n\t\t\t\t\tif (auto n = ledgeUrl.find(\"https://\"); n != std::string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tledgeHost = ledgeUrl.substr(n + strlen(\"https://\"));\n\t\t\t\t\t}\n\t\t\t\t\tledgeHeader += \"Host: \" + ledgeHost + \"\\r\\n\";\n\n\t\t\t\t\tif (strlen(urlText) == 0 || strcmp(urlText, localhostUrl.c_str()) == 0\n\t\t\t\t\t\t|| strcmp(urlText, storeUrl.c_str()) == 0 || strcmp(urlText, ledgeUrl.c_str()) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::strcpy(urlText, ledgeUrl.c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstd::string sessionToken = LCU::Request(\"GET\", \"/lol-league-session/v1/league-session-token\");\n\t\t\t\tstd::erase(sessionToken, '\\\"');\n\n\t\t\t\tledgeHeader += \"Accept-Encoding: deflate, \"/*gzip, */\"zstd\\r\\n\";\n\t\t\t\tledgeHeader += \"user-agent: LeagueOfLegendsClient/\" + LCU::league.version + \"\\r\\n\";\n\t\t\t\tledgeHeader += \"Authorization: Bearer \" + sessionToken + \"\\r\\n\";\n\t\t\t\tledgeHeader += \"Content-type: application/json\\r\\n\";\n\t\t\t\tledgeHeader += \"Accept: application/json\\r\\n\";\n\n\t\t\t\tif (strlen(method) != 0)\n\t\t\t\t{\n\t\t\t\t\tstd::strcpy(method, Utils::ToUpper(std::string(method)).c_str());\n\t\t\t\t}\n\n\t\t\t\tstd::strcpy(inputPort, \"443\");\n\t\t\t\tstd::strcpy(inputHeader, ledgeHeader.c_str());\n\t\t\t}\n\n\t\t\tImGui::Text(\"Header:\");\n\t\t\tImGui::InputTextMultiline(\"##inputHeader\", (inputHeader), IM_ARRAYSIZE(inputHeader), ImVec2(S.Window.width - 130.f,\n\t\t\t\t(label_size.y + ImGui::GetStyle().FramePadding.y) * 6.f), ImGuiInputTextFlags_AllowTabInput);\n\n\t\t\tS.customTab.port = inputPort;\n\t\t\tS.customTab.header = inputHeader;\n\n\t\t\tif (!S.customTab.port.empty())\n\t\t\t\tcustomPort = std::stoi(S.customTab.port);\n\t\t\telse\n\t\t\t\tcustomPort = 443;\n\n\t\t\tcustomHeader = S.customTab.header;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tisCustomOpen = false;\n\t\t\tcustomHeader = LCU::league.header;\n\t\t\tcustomPort = LCU::league.port;\n\t\t}\n\n\t\tImGui::Columns(2, nullptr, false);\n\n\t\tstatic std::string result;\n\t\tif (ImGui::Button(\"Send custom request##customTab\"))\n\t\t{\n\t\t\tauto sURL = std::string(urlText);\n\n\t\t\tif (sURL.find(\"https://127.0.0.1\") == std::string::npos && !isCustomOpen)\n\t\t\t{\n\t\t\t\tif (sURL.find(\"https://\") == std::string::npos && sURL.find(\"http://\") == std::string::npos)\n\t\t\t\t{\n\t\t\t\t\twhile (sURL[0] == ' ' || sURL[0] == '\\n')\n\t\t\t\t\t\tsURL.erase(sURL.begin());\n\t\t\t\t\tif (sURL[0] != '/')\n\t\t\t\t\t\tsURL.insert(0, \"/\");\n\t\t\t\t\tsURL.insert(0, \"https://127.0.0.1:\" + std::to_string(LCU::league.port));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (sURL.find(\"https://127.0.0.1:\") == std::string::npos && !isCustomOpen)\n\t\t\t{\n\t\t\t\tsURL.insert(strlen(\"https://127.0.0.1\"), \":\" + std::to_string(LCU::league.port));\n\t\t\t}\n\t\t\telse if (sURL.find(\"https://\") != std::string::npos || sURL.find(\"https://\") != std::string::npos)\n\t\t\t{\n\t\t\t\tif (customPort != 443 && customPort != 80)\n\t\t\t\t{\n\t\t\t\t\tsURL.insert(sURL.find(\"/\", strlen(\"https://\")), \":\" + std::to_string(customPort));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcpr::Session customSession;\n\t\t\tcustomSession.SetVerifySsl(false);\n\t\t\tcustomSession.SetHeader(Utils::StringToHeader(customHeader));\n\t\t\tcustomSession.SetBody(requestText);\n\t\t\tcustomSession.SetUrl(sURL);\n\n\t\t\tcpr::Response r;\n\n\t\t\tconst std::string upperMethod = Utils::ToUpper(method);\n\t\t\tif (upperMethod == \"GET\")\n\t\t\t{\n\t\t\t\tr = customSession.Get();\n\t\t\t}\n\t\t\telse if (upperMethod == \"POST\")\n\t\t\t{\n\t\t\t\tr = customSession.Post();\n\t\t\t}\n\t\t\telse if (upperMethod == \"OPTIONS\")\n\t\t\t{\n\t\t\t\tr = customSession.Options();\n\t\t\t}\n\t\t\telse if (upperMethod == \"DELETE\")\n\t\t\t{\n\t\t\t\tr = customSession.Delete();\n\t\t\t}\n\t\t\telse if (upperMethod == \"PUT\")\n\t\t\t{\n\t\t\t\tr = customSession.Put();\n\t\t\t}\n\t\t\telse if (upperMethod == \"HEAD\")\n\t\t\t{\n\t\t\t\tr = customSession.Head();\n\t\t\t}\n\t\t\telse if (upperMethod == \"PATCH\")\n\t\t\t{\n\t\t\t\tr = customSession.Patch();\n\t\t\t}\n\n\t\t\tresult = r.text;\n\t\t}\n\n\t\tImGui::SameLine();\n\n\t\tstatic Json::StreamWriterBuilder wBuilder;\n\t\tstatic std::string sResultJson;\n\t\tstatic char* cResultJson;\n\n\t\tif (ImGui::Button(\"Format JSON##customTab\"))\n\t\t{\n\t\t\tif (!sResultJson.empty())\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(sResultJson.c_str(), sResultJson.c_str() + static_cast<int>(sResultJson.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tsResultJson = Json::writeString(wBuilder, root);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tImGui::NextColumn();\n\n\t\tImGui::Text(\"Endpoints list:\");\n\t\tImGui::TextURL(\"LCU\", \"https://lcu.kebs.dev\", 1, 0);\n\t\tImGui::SameLine();\n\t\tImGui::Text(\" | \");\n\t\tImGui::TextURL(\"Riot Client\", \"https://riotclient.kebs.dev\", 1, 0);\n\n\t\tImGui::Columns(1);\n\n\t\tif (!result.empty())\n\t\t{\n\t\t\tJson::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING err;\n\t\t\tJson::Value root;\n\t\t\tif (!reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err) || isCustomOpen)\n\t\t\t\tsResultJson = result;\n\t\t\telse\n\t\t\t{\n\t\t\t\tsResultJson = Json::writeString(wBuilder, root);\n\t\t\t}\n\t\t\tresult = \"\";\n\t\t}\n\n\t\tif (!sResultJson.empty())\n\t\t{\n\t\t\tcResultJson = sResultJson.data();\n\t\t\tImGui::InputTextMultiline(\"##customResult\", cResultJson, sResultJson.size() + 1, ImVec2(S.Window.width - 130.f,\n\t\t\t\t(label_size.y + ImGui::GetStyle().FramePadding.y) * 19.f));\n\t\t}\n\t}\n\n\tstatic void Invoke()\n\t{\n\t\tstatic bool once = true;\n\n\t\tstatic char destination[1024];\n\t\tstatic char method[1024];\n\t\tstatic char args[1024 * 32];\n\n\t\tif (once)\n\t\t{\n\t\t\tonce = false;\n\t\t\tstd::ranges::copy(S.invokeTab.destination, destination);\n\t\t\tstd::ranges::copy(S.invokeTab.method, method);\n\t\t\tstd::ranges::copy(S.invokeTab.args, args);\n\t\t}\n\n\t\tImGui::Text(\"Destination:\");\n\t\tImGui::InputTextMultiline(\"##inputDestination\", destination, IM_ARRAYSIZE(destination), ImVec2(600, 20));\n\n\t\tImGui::Text(\"Method:\");\n\t\tImGui::InputTextMultiline(\"##inputMethod\", method, IM_ARRAYSIZE(method), ImVec2(600, 20));\n\n\t\tImGui::Text(\"Args:\");\n\t\tImGui::InputTextMultiline(\"##inputArgs\", args, IM_ARRAYSIZE(args), ImVec2(600, 50));\n\n\t\tS.invokeTab.destination = destination;\n\t\tS.invokeTab.method = method;\n\t\tS.invokeTab.args = args;\n\n\t\tstatic std::string result;\n\t\tif (ImGui::Button(\"Submit##submitInvoke\"))\n\t\t{\n\t\t\tconst std::string req = std::format(\"https://127.0.0.1/lol-login/v1/session/invoke?destination={0}&method={1}&args=[{2}]\",\n\t\t\t\tdestination, method, args);\n\t\t\tresult = LCU::Request(\"POST\", req, \"\");\n\t\t}\n\n\t\tImGui::Text(\"Result:\");\n\t\tImGui::SameLine();\n\n\t\tif (ImGui::Button(\"Copy to clipboard##invokeTab\"))\n\t\t{\n\t\t\tUtils::CopyToClipboard(result);\n\t\t}\n\n\t\tstatic Json::StreamWriterBuilder wBuilder;\n\t\tstatic std::string sResultJson;\n\t\tstatic char* cResultJson;\n\n\t\tif (!result.empty())\n\t\t{\n\t\t\tconst Json::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING err;\n\t\t\tJson::Value root;\n\t\t\tif (!reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t\t\tsResultJson = result;\n\t\t\telse\n\t\t\t{\n\t\t\t\tsResultJson = Json::writeString(wBuilder, root);\n\t\t\t}\n\t\t\tresult = \"\";\n\t\t}\n\n\t\tif (!sResultJson.empty())\n\t\t{\n\t\t\tcResultJson = sResultJson.data();\n\t\t\tImGui::InputTextMultiline(\"##gameResult\", cResultJson, sResultJson.size() + 1, ImVec2(600, 232));\n\t\t}\n\t}\n\nprivate:\n\tstatic inline bool onOpen = true;\n\npublic:\n\tstatic void Render()\n\t{\n\t\tif (ImGui::BeginTabItem(\"Custom\"))\n\t\t{\n\t\t\tif (ImGui::BeginTabBar(\"TabBar\"))\n\t\t\t{\n\t\t\t\tif (ImGui::BeginTabItem(\"HTTP/HTTPS\"))\n\t\t\t\t{\n\t\t\t\t\tCustom();\n\t\t\t\t\tImGui::EndTabItem();\n\t\t\t\t}\n\t\t\t\tif (ImGui::BeginTabItem(\"LCDS\"))\n\t\t\t\t{\n\t\t\t\t\tInvoke();\n\t\t\t\t\tImGui::EndTabItem();\n\t\t\t\t}\n\t\t\t\tImGui::EndTabBar();\n\t\t\t}\n\n\t\t\tif (onOpen)\n\t\t\t\tonOpen = false;\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tonOpen = true;\n\t\t}\n\t}\n\nprivate:\n\tstatic std::string GetLedgeUrl()\n\t{\n\t\tJson::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value rootRegion;\n\t\tstd::string region;\n\t\tstd::string getRegion = LCU::Request(\"GET\", \"/riotclient/get_region_locale\");\n\t\tif (reader->parse(getRegion.c_str(), getRegion.c_str() + static_cast<int>(getRegion.length()), &rootRegion, &err))\n\t\t{\n\t\t\tregion = rootRegion[\"webRegion\"].asString();\n\t\t}\n\n\t\tif (!region.empty())\n\t\t{\n\t\t\tstd::ifstream systemYaml(S.leaguePath + \"system.yaml\");\n\t\t\tstd::string line;\n\t\t\twhile (std::getline(systemYaml, line))\n\t\t\t{\n\t\t\t\tif (line.find(\"league_edge_url: \") != std::string::npos\n\t\t\t\t\t&& line.find(region) != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tstd::string league_edge_url = line;\n\t\t\t\t\tleague_edge_url = league_edge_url.substr(league_edge_url.find(\"league_edge_url: \") + strlen(\"league_edge_url: \"));\n\t\t\t\t\tsystemYaml.close();\n\t\t\t\t\treturn league_edge_url;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsystemYaml.close();\n\t\t}\n\t\treturn \"\";\n\t}\n};\n"
  },
  {
    "path": "KBotExt/Definitions.h",
    "content": "#pragma once\n\n#include <vector>\n#include <string>\n\nstruct ChampMinimal\n{\n\tbool active;\n\tstd::string alias;\n\tstd::string banVoPath;\n\tstd::string baseLoadScreenPath;\n\tbool botEnabled;\n\tstd::string chooseVoPath;\n\t//disabledQueues\n\tbool freeToPlay;\n\tint id;\n\tstd::string name;\n\n\t//ownership\n\tbool freeToPlayReward;\n\tint owned;\n\n\tstd::string purchased;\n\tbool rankedPlayEnabled;\n\tstd::pair<std::string, std::string> roles;\n\tstd::string squarePortraitPath;\n\tstd::string stingerSfxPath;\n\tstd::string title;\n};\n\nstruct ChampMastery\n{\n\tint championId;\n\tint championLevel;\n\tint championPoints = 0;\n\tint championPointsSinceLastLevel;\n\tint championPointsUntilNextLevel;\n\tbool chestGranted;\n\tstd::string formattedChampionPoints;\n\tstd::string formattedMasteryGoal;\n\tstd::string highestGrade;\n\tstd::string lastPlayTime;\n\tstd::string playerId;\n\tint tokensEarned;\n};\n\nstruct ChampAll\n{\n\tChampMinimal min;\n\tChampMastery mas;\n};\n\ninline std::vector<ChampMinimal> champsMinimal;\ninline std::vector<ChampMastery> champsMastery;\ninline std::vector<ChampAll> champsAll;\n\nstruct Skin\n{\n\tstd::string name;\n\tstd::string inventoryType;\n\tint itemId;\n\tstd::string ownershipType;\n\tbool isVintage;\n\ttm purchaseDate;\n\tint quantity;\n\tstd::string uuid;\n};\n\ninline std::vector<Skin> ownedSkins;\n\nenum QueueID\n{\n\tDraftPick = 400,\n\tSoloDuo = 420,\n\tBlindPick = 430,\n\tFlex = 440,\n\tARAM = 450,\n\tQuickplay = 490,\n\tClash = 700,\n\tIntroBots = 870,\n\tBeginnerBots = 880,\n\tIntermediateBots = 890,\n\tARURF = 900,\n\tTFTNormal = 1090,\n\tTFTRanked = 1100,\n\tTFTTutorial = 1110,\n\tTFTHyperRoll = 1130,\n\tTFTDoubleUp = 1160,\n\tNexusBlitz = 1300,\n\tUltimateSpellbook = 1400,\n\tTutorial1 = 2000,\n\tTutorial2 = 2010,\n\tTutorial3 = 2020,\n};\n\nstruct Champ\n{\n\tint key;\n\tstd::string name;\n\tstd::vector<std::pair<std::string, std::string>> skins;\n};\n\ninline std::vector<Champ> champSkins;\n"
  },
  {
    "path": "KBotExt/DirectX.cpp",
    "content": "﻿#include \"DirectX.h\"\n\n#include \"GameTab.h\"\n#include \"InfoTab.h\"\n#include \"LoginTab.h\"\n#include \"ProfileTab.h\"\n#include \"MiscTab.h\"\n#include \"CustomTab.h\"\n#include \"SkinsTab.h\"\n#include \"ChampsTab.h\"\n#include \"SettingsTab.h\"\n\nbool Direct3D11Render::DirectXInit(const HWND hWnd)\n{\n\t// Setup swap chain\n\tDXGI_SWAP_CHAIN_DESC sd;\n\tZeroMemory(&sd, sizeof(sd));\n\tsd.BufferCount = 2;\n\tsd.BufferDesc.Width = 0;\n\tsd.BufferDesc.Height = 0;\n\tsd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\tsd.BufferDesc.RefreshRate.Numerator = 60;\n\tsd.BufferDesc.RefreshRate.Denominator = 1;\n\tsd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n\tsd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n\tsd.OutputWindow = hWnd;\n\tsd.SampleDesc.Count = 1;\n\tsd.SampleDesc.Quality = 0;\n\tsd.Windowed = TRUE;\n\tsd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;\n\n\t//createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;\n\tD3D_FEATURE_LEVEL featureLevel;\n\tconstexpr D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };\n\tif (constexpr UINT createDeviceFlags = 0; D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags,\n\t\tfeatureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain,\n\t\t&g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK)\n\t\treturn false;\n\n\tif (!CreateRenderTarget())\n\t\treturn false;\n\n\tRenderimgui(hWnd);\n\n\tMisc::CheckVersion();\n\n\tif (S.checkPrerelease)\n\t\tMisc::CheckPrerelease(S.fileName);\n\n\tgamePatch = Misc::GetCurrentPatch();\n\n\tstd::thread t{ Misc::GetAllChampionSkins };\n\tt.detach();\n\n\tstd::thread AutoAcceptThread(&GameTab::AutoAccept);\n\tAutoAcceptThread.detach();\n\n\treturn true;\n}\n\nvoid Direct3D11Render::StartFrame()\n{\n\t// Start the Dear ImGui frame\n\tImGui_ImplDX11_NewFrame();\n\tImGui_ImplWin32_NewFrame();\n\tImGui::NewFrame();\n}\n\nvoid Direct3D11Render::EndFrame()\n{\n\t// Rendering\n\tauto clear_color = ImVec4(0, 0, 0, 255.f);\n\tImGui::EndFrame();\n\tImGui::Render();\n\tg_pd3dDeviceContext->OMSetRenderTargets(1, &g_pd3dRenderTargetView, nullptr);\n\tg_pd3dDeviceContext->ClearRenderTargetView(g_pd3dRenderTargetView, reinterpret_cast<float*>(&clear_color));\n\tImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());\n\n\tg_pSwapChain->Present(1, 0); // Present with vsync\n\t//g_pSwapChain->Present(0, 0); // Present without vsync\n}\n\nint Direct3D11Render::Render() const\n{\n\tstatic char buf[255];\n\tstatic std::string connectedTo = \"\";\n\tstatic std::string currentInfo = \"\";\n\tif (gamePatch == \"0.0.0\")\n\t{\n\t\tcurrentInfo = \"Failed to connect, most likely blocked by antivirus or firewall\";\n\t}\n\telse\n\t{\n\t\tif (LCU::IsProcessGood())\n\t\t\tconnectedTo = \"| Connected to: \" + LCU::leagueProcesses[LCU::indexLeagueProcesses].second;\n\n\t\tif (champSkins.empty())\n\t\t\tcurrentInfo = \"Fetching skin data...\";\n\t\telse\n\t\t\tcurrentInfo = \"\";\n\t}\n\n\tsprintf_s(buf, (\"KBotExt by kebs - %s %s \\t %s ###AnimatedTitle\"), gamePatch.c_str(), connectedTo.c_str(), currentInfo.c_str());\n\n\tImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_FirstUseEver);\n\tImGui::SetNextWindowSize(ImVec2(685, 462), ImGuiCond_FirstUseEver);\n\tImGui::SetNextWindowSize(ImVec2(static_cast<float>(S.Window.width - 15), static_cast<float>(S.Window.height - 38)));\n\tconstexpr ImGuiWindowFlags flags = /*ImGuiWindowFlags_NoTitleBar |*/ ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |\n\t\tImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;\n\tImGui::Begin(buf, nullptr, flags); // , ImGuiWindowFlags_AlwaysAutoResize);\n\tif (constexpr ImGuiTabBarFlags tab_bar_flags = 0; ImGui::BeginTabBar(\"TabBar\", tab_bar_flags))\n\t{\n\t\tif (!closedClient)\n\t\t{\n\t\t\tGameTab::Render();\n\n\t\t\tProfileTab::Render();\n\n\t\t\tInfoTab::Render();\n\n\t\t\tChampsTab::Render();\n\n\t\t\tSkinsTab::Render();\n\n\t\t\tMiscTab::Render();\n\n\t\t\tCustomTab::Render();\n\n\t\t\tSettingsTab::Render();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLoginTab::Render();\n\n\t\t\tSettingsTab::Render();\n\t\t}\n\t\tImGui::EndTabBar();\n\t}\n\n\tImGui::End();\n\n\treturn 1;\n}\n\nvoid Direct3D11Render::Shutdown()\n{\n\tCleanupRenderTarget();\n\tif (g_pSwapChain)\n\t{\n\t\tg_pSwapChain->Release();\n\t\tg_pSwapChain = nullptr;\n\t}\n\tif (g_pd3dDeviceContext)\n\t{\n\t\tg_pd3dDeviceContext->Release();\n\t\tg_pd3dDeviceContext = nullptr;\n\t}\n\tif (g_pd3dDevice)\n\t{\n\t\tg_pd3dDevice->Release();\n\t\tg_pd3dDevice = nullptr;\n\t}\n}\n\nbool Direct3D11Render::CreateRenderTarget()\n{\n\tID3D11Texture2D* pBackBuffer;\n\tif (S_OK != g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)))\n\t\treturn false;\n\tif (S_OK != g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pd3dRenderTargetView))\n\t\treturn false;\n\tpBackBuffer->Release();\n\treturn true;\n}\n\nvoid Direct3D11Render::CleanupRenderTarget()\n{\n\tif (g_pd3dRenderTargetView)\n\t{\n\t\tg_pd3dRenderTargetView->Release();\n\t\tg_pd3dRenderTargetView = nullptr;\n\t}\n}\n\nvoid Direct3D11Render::Renderimgui(const HWND hWnd)\n{\n\t// Setup Dear ImGui context\n\tIMGUI_CHECKVERSION();\n\tImGui::CreateContext();\n\n\t// Setup Dear ImGui style\n\tMenuInit();\n\n\t// Setup Platform/Renderer back-ends\n\tImGui_ImplWin32_Init(hWnd);\n\tImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);\n}\n\nvoid Direct3D11Render::InitializeFonts()\n{\n\tconst ImGuiIO& io = ImGui::GetIO();\n\t(void)io;\n\n\tstatic constexpr ImWchar ranges[] = { 0x1, 0x1FFFF, 0 };\n\tstatic ImFontConfig cfg;\n\tcfg.OversampleH = cfg.OversampleV = 1;\n\n\tio.Fonts->AddFontDefault(&cfg);\n\n\tcfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_LoadColor;\n\tcfg.MergeMode = true;\n\n\tusing tSHGetFolderPathW = HRESULT(WINAPI*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);\n\tconst auto SHGetFolderPathW = reinterpret_cast<tSHGetFolderPathW>(GetProcAddress(LoadLibraryW(L\"shell32.dll\"), \"SHGetFolderPathW\"));\n\n\tTCHAR szPath[MAX_PATH];\n\tif (SUCCEEDED(SHGetFolderPathW(NULL, 0x0024/*CSIDL_WINDOWS*/, NULL, 0, szPath)))\n\t{\n\t\tstd::filesystem::path fontsPath(szPath);\n\t\tfontsPath = fontsPath / \"Fonts\";\n\n\t\tif (is_directory(fontsPath))\n\t\t{\n\t\t\tfor (const std::vector<std::string> fonts = {\n\t\t\t\t\t \"seguiemj.ttf\", // emojis\n\t\t\t\t\t \"segoeuib.ttf\", // cyrillic\n\t\t\t\t\t \"malgunbd.ttf\", // korean\n\t\t\t\t\t \"YuGothB.ttc\", // japanese\n\t\t\t\t\t \"simsun.ttc\", // simplified chinese\n\t\t\t\t\t \"msjh.ttc\", // traditional chinese\n\t\t\t\t\t \"seguisym.ttf\", // symbols\n\t\t\t\t}; const auto & f : fonts)\n\t\t\t{\n\t\t\t\tif (const std::filesystem::path path = fontsPath / f; exists(path))\n\t\t\t\t{\n\t\t\t\t\tio.Fonts->AddFontFromFileTTF(path.string().c_str(), 13.0f, &cfg, ranges);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Direct3D11Render::MenuInit()\n{\n\tImGuiIO& io = ImGui::GetIO();\n\t(void)io;\n\tio.IniFilename = nullptr;\n\tio.LogFilename = nullptr;\n\tio.FontGlobalScale = S.fontScale;\n\n\tInitializeFonts();\n\n\tImGuiStyle& style = ImGui::GetStyle();\n\n\t//Main\n\tstyle.WindowPadding = ImVec2(4.f, 4.f);\n\tstyle.FramePadding = ImVec2(3.f, 3.f);\n\tstyle.ItemSpacing = ImVec2(5.f, 5.f);\n\tstyle.ItemInnerSpacing = ImVec2(5.f, 5.f);\n\tstyle.TouchExtraPadding = ImVec2(0.f, 0.f);\n\tstyle.ScrollbarSize = 15.f;\n\tstyle.GrabMinSize = 15.f;\n\t//Borders\n\tstyle.WindowBorderSize = 1.f;\n\tstyle.ChildBorderSize = 1.f;\n\tstyle.PopupBorderSize = 1.f;\n\tstyle.FrameBorderSize = 1.f;\n\tstyle.TabBorderSize = 1.f;\n\t//Rounding\n\tstyle.WindowRounding = 0.f;\n\tstyle.ChildRounding = 0.f;\n\tstyle.FrameRounding = 0.f;\n\tstyle.PopupRounding = 0.f;\n\tstyle.ScrollbarRounding = 0.f;\n\tstyle.GrabRounding = 0.f;\n\tstyle.LogSliderDeadzone = 5.f;\n\tstyle.TabRounding = 0.f;\n\t//Alignment\n\tstyle.WindowTitleAlign = ImVec2(0.f, 0.f);\n\tstyle.WindowMenuButtonPosition = 0;\n\tstyle.ColorButtonPosition = 1;\n\tstyle.ButtonTextAlign = ImVec2(0.5f, 0.5f);\n\tstyle.SelectableTextAlign = ImVec2(0.5f, 0.5f);\n\t//AntiAliasing\n\tstyle.AntiAliasedLines = false;\n\tstyle.AntiAliasedLinesUseTex = false;\n\tstyle.AntiAliasedFill = false;\n\n\tImVec4* colors = ImGui::GetStyle().Colors;\n\tcolors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);\n\tcolors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_ChildBg] = ImVec4(0.01f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_PopupBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 0.20f);\n\tcolors[ImGuiCol_BorderShadow] = ImVec4(1.00f, 1.00f, 1.00f, 0.04f);\n\tcolors[ImGuiCol_FrameBg] = ImVec4(0.01f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_FrameBgHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.39f);\n\tcolors[ImGuiCol_FrameBgActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.39f);\n\tcolors[ImGuiCol_TitleBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_TitleBgActive] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.01f, 0.00f, 0.00f, 0.51f);\n\tcolors[ImGuiCol_MenuBarBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_ScrollbarBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);\n\tcolors[ImGuiCol_ScrollbarGrab] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 0.50f);\n\tcolors[ImGuiCol_ScrollbarGrabActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_CheckMark] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_SliderGrab] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_SliderGrabActive] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_Button] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_ButtonHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_ButtonActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_Header] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_HeaderHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_HeaderActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_SeparatorHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_SeparatorActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_ResizeGrip] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_ResizeGripHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_Tab] = ImVec4(0.39f, 0.39f, 0.39f, 0.39f);\n\tcolors[ImGuiCol_TabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_TabActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.63f);\n\tcolors[ImGuiCol_TabUnfocused] = ImVec4(0.07f, 0.10f, 0.15f, 0.97f);\n\tcolors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.14f, 0.26f, 0.42f, 1.00f);\n\tcolors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);\n\tcolors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);\n\tcolors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);\n\tcolors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);\n\tcolors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);\n\tcolors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);\n}"
  },
  {
    "path": "KBotExt/DirectX.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <d3d11.h>\n#define DIRECTINPUT_VERSION 0x0800\n#pragma comment(lib, \"dcomp.lib\")\n#pragma comment(lib, \"d3d11.lib\")\n\n// Data\ninline ID3D11Device* g_pd3dDevice = nullptr;\ninline ID3D11DeviceContext* g_pd3dDeviceContext = nullptr;\ninline ID3D11RenderTargetView* g_pd3dRenderTargetView = nullptr;\ninline IDXGISwapChain* g_pSwapChain = nullptr;\n\nclass Direct3D11Render\n{\n\tstd::string gamePatch;\n\npublic:\n\tbool closedClient = false;\n\n\tDirect3D11Render() = default;\n\n\t~Direct3D11Render() = default;\n\n\tstatic void StartFrame();\n\n\tstatic void EndFrame();\n\n\t// initializes directx, fonts, imgui and objects\n\tbool DirectXInit(HWND hWnd);\n\n\tstatic bool CreateRenderTarget();\n\n\tstatic void CleanupRenderTarget();\n\n\t// main rendering loop\n\tint Render() const;\n\n\t//releases directx and clears imgui\n\tstatic void Shutdown();\n\n\t//initializes imgui\n\tvoid Renderimgui(HWND hWnd);\n\n\tstatic void InitializeFonts();\n\n\t//initializes imgui styles\n\tstatic void MenuInit();\n};\n"
  },
  {
    "path": "KBotExt/GameTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"LCU.h\"\n#include \"Utils.h\"\n#include \"Misc.h\"\n\nclass GameTab\n{\nprivate:\n\tstatic inline bool onOpen = true;\n\npublic:\n\tstatic void Render()\n\t{\n\t\tif (ImGui::BeginTabItem(\"Game\"))\n\t\t{\n\t\t\tstatic std::string result;\n\t\t\tstatic std::string custom;\n\n\t\t\tstatic std::vector<std::pair<long, std::string>> gamemodes;\n\n\t\t\tif (onOpen)\n\t\t\t{\n\t\t\t\tif (gamemodes.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string getQueues = LCU::Request(\"GET\", \"/lol-game-queues/v1/queues\");\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (reader->parse(getQueues.c_str(), getQueues.c_str() + static_cast<int>(getQueues.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < root.size(); i++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (root[i][\"queueAvailability\"].asString() != \"Available\")\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\tint64_t id = root[i][\"id\"].asInt64();\n\t\t\t\t\t\t\t\tstd::string name = root[i][\"name\"].asString();\n\t\t\t\t\t\t\t\tname += \" \" + std::to_string(id);\n\t\t\t\t\t\t\t\t//std::cout << id << \" \" << name << std::endl;\n\t\t\t\t\t\t\t\tstd::pair<long, std::string> temp = { id, name };\n\t\t\t\t\t\t\t\tgamemodes.emplace_back(temp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstd::ranges::sort(gamemodes, [](auto& left, auto& right) {\n\t\t\t\t\t\t\t\treturn left.first < right.first;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic std::vector<std::string> firstPosition = { \"UNSELECTED\", \"TOP\", \"JUNGLE\", \"MIDDLE\", \"BOTTOM\", \"UTILITY\", \"FILL\" };\n\t\t\tstatic std::vector<std::string> secondPosition = { \"UNSELECTED\", \"TOP\", \"JUNGLE\", \"MIDDLE\", \"BOTTOM\", \"UTILITY\", \"FILL\" };\n\n\t\t\tstatic int gameID = 0;\n\n\t\t\tImGui::Columns(4, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Quickplay\"))\n\t\t\t\tgameID = Quickplay;\n\n\t\t\tif (ImGui::Button(\"Draft pick\"))\n\t\t\t\tgameID = DraftPick;\n\n\t\t\tif (ImGui::Button(\"Solo/Duo\"))\n\t\t\t\tgameID = SoloDuo;\n\n\t\t\tif (ImGui::Button(\"Flex\"))\n\t\t\t\tgameID = Flex;\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"ARAM\"))\n\t\t\t\tgameID = ARAM;\n\n\t\t\tif (ImGui::Button(\"ARURF\"))\n\t\t\t\tgameID = ARURF;\n\n\t\t\tif (ImGui::Button(\"Ultimate Spellbook\"))\n\t\t\t\tgameID = UltimateSpellbook;\n\n\t\t\tif (ImGui::Button(\"ARURF 1V1 (PBE)\"))\n\t\t\t\tgameID = 901;\n\n\t\t\t/*if (ImGui::Button(\"URF\"))\n\t\t\t\tgameID = 318;*/\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"TFT Normal\"))\n\t\t\t\tgameID = TFTNormal;\n\n\t\t\tif (ImGui::Button(\"TFT Ranked\"))\n\t\t\t\tgameID = TFTRanked;\n\n\t\t\tif (ImGui::Button(\"TFT Hyper Roll\"))\n\t\t\t\tgameID = TFTHyperRoll;\n\n\t\t\tif (ImGui::Button(\"TFT Double Up\"))\n\t\t\t\tgameID = TFTDoubleUp;\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"TFT Tutorial\"))\n\t\t\t\tgameID = TFTTutorial;\n\n\t\t\tif (ImGui::Button(\"Practice Tool\"))\n\t\t\t{\n\t\t\t\tcustom =\n\t\t\t\t\tR\"({\"customGameLobby\":{\"configuration\":{\"gameMode\":\"PRACTICETOOL\",\"gameMutator\":\"\",\"gameServerRegion\":\"\",\"mapId\":11,\"mutators\":{\"id\":1},\"spectatorPolicy\":\"AllAllowed\",\"teamSize\":1},\"lobbyName\":\"KBot\",\"lobbyPassword\":null},\"isCustom\":true})\";\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Practice Tool 5v5\"))\n\t\t\t{\n\t\t\t\tcustom =\n\t\t\t\t\tR\"({\"customGameLobby\":{\"configuration\":{\"gameMode\":\"PRACTICETOOL\",\"gameMutator\":\"\",\"gameServerRegion\":\"\",\"mapId\":11,\"mutators\":{\"id\":1},\"spectatorPolicy\":\"AllAllowed\",\"teamSize\":5},\"lobbyName\":\"KBot\",\"lobbyPassword\":null},\"isCustom\":true})\";\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Clash\"))\n\t\t\t\tgameID = Clash;\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(4, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Tutorial 1\"))\n\t\t\t\tgameID = Tutorial1;\n\n\t\t\tif (ImGui::Button(\"Tutorial 2\"))\n\t\t\t\tgameID = Tutorial2;\n\n\t\t\tif (ImGui::Button(\"Tutorial 3\"))\n\t\t\t\tgameID = Tutorial3;\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Intro Bots\"))\n\t\t\t\tgameID = IntroBots;\n\n\t\t\tif (ImGui::Button(\"Beginner Bots\"))\n\t\t\t\tgameID = BeginnerBots;\n\n\t\t\tif (ImGui::Button(\"Intermediate Bots\"))\n\t\t\t\tgameID = IntermediateBots;\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Custom Blind\"))\n\t\t\t\tcustom =\n\t\t\t\tR\"({\"customGameLobby\":{\"configuration\":{\"gameMode\":\"CLASSIC\",\"gameMutator\":\"\",\"gameServerRegion\":\"\",\"mapId\":11,\"mutators\":{\"id\":1},\"spectatorPolicy\":\"AllAllowed\",\"teamSize\":5},\"lobbyName\":\"KBot\",\"lobbyPassword\":null},\"isCustom\":true})\";\n\n\t\t\tif (ImGui::Button(\"Custom ARAM\"))\n\t\t\t\tcustom =\n\t\t\t\tR\"({\"customGameLobby\":{\"configuration\":{\"gameMode\":\"ARAM\",\"gameMutator\":\"\",\"gameServerRegion\":\"\",\"mapId\":12,\"mutators\":{\"id\":1},\"spectatorPolicy\":\"AllAllowed\",\"teamSize\":5},\"lobbyName\":\"KBot\",\"lobbyPassword\":null},\"isCustom\":true})\";\n\n\t\t\t//\"id\" 1- blind 2- draft -4 all random 6- tournament draft\n\n\t\t\tstatic int indexGamemodes = -1;\n\t\t\tauto labelGamemodes = \"All Gamemodes\";\n\t\t\tif (indexGamemodes != -1)\n\t\t\t\tlabelGamemodes = gamemodes[indexGamemodes].second.c_str();\n\n\t\t\tif (ImGui::BeginCombo(\"##combolGamemodes\", labelGamemodes, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < gamemodes.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = indexGamemodes == n;\n\t\t\t\t\tif (ImGui::Selectable(gamemodes[n].second.c_str(), is_selected))\n\t\t\t\t\t\tindexGamemodes = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Create##gamemode\"))\n\t\t\t{\n\t\t\t\tgameID = gamemodes[indexGamemodes].first;\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tstatic std::vector<std::pair<int, std::string>> botChamps;\n\t\t\tstatic size_t indexBots = 0; // Here we store our selection data as an index.\n\t\t\tauto labelBots = \"Bot\";\n\t\t\tif (!botChamps.empty())\n\t\t\t\tlabelBots = botChamps[indexBots].second.c_str();\n\t\t\tif (ImGui::BeginCombo(\"##comboBots\", labelBots, 0))\n\t\t\t{\n\t\t\t\tif (botChamps.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string getBots = LCU::Request(\"GET\", \"https://127.0.0.1/lol-lobby/v2/lobby/custom/available-bots\");\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (reader->parse(getBots.c_str(), getBots.c_str() + static_cast<int>(getBots.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::pair temp = { i[\"id\"].asInt(), i[\"name\"].asString() };\n\t\t\t\t\t\t\t\tbotChamps.emplace_back(temp);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstd::ranges::sort(botChamps, [](std::pair<int, std::string> a, std::pair<int, std::string> b) {\n\t\t\t\t\t\t\t\treturn a.second < b.second;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (size_t n = 0; n < botChamps.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (indexBots == n);\n\t\t\t\t\tif (ImGui::Selectable(botChamps[n].second.c_str(), is_selected))\n\t\t\t\t\t\tindexBots = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\t\t\tstd::vector<std::string> difficulties = { \"NONE\", \"EASY\", \"MEDIUM\", \"HARD\", \"UBER\", \"TUTORIAL\", \"INTRO\" };\n\t\t\tstatic size_t indexDifficulty = 0; // Here we store our selection data as an index.\n\t\t\tconst char* labelDifficulty = difficulties[indexDifficulty].c_str();\n\n\t\t\tif (ImGui::BeginCombo(\"##comboDifficulty\", labelDifficulty, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < difficulties.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (indexDifficulty == n);\n\t\t\t\t\tif (ImGui::Selectable(difficulties[n].c_str(), is_selected))\n\t\t\t\t\t\tindexDifficulty = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\t\t\tstatic int botTeam = 0;\n\n\t\t\tif (ImGui::Button(\"Add bot##addBot\"))\n\t\t\t{\n\t\t\t\tif (botChamps.empty())\n\t\t\t\t{\n\t\t\t\t\tMessageBoxA(nullptr, \"Pick the bots champion first\", \"Adding bots failed\", MB_OK);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstd::string team = botTeam ? R\"(,\"teamId\":\"200\"})\" : R\"(,\"teamId\":\"100\"})\";\n\t\t\t\t\tstd::string body = R\"({\"botDifficulty\":\")\" + difficulties[indexDifficulty] + R\"(\",\"championId\":)\" + std::to_string(\n\t\t\t\t\t\tbotChamps[indexBots].first) + team;\n\t\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v1/lobby/custom/bots\", body);\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Blue\", &botTeam, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Red\", &botTeam, 1);\n\n\t\t\tImGui::Columns(1);\n\n\t\t\t//ImGui::Separator();\n\t\t\t//static int inputGameID = 0;\n\t\t\t//ImGui::InputInt(\"##inputGameID:\", &inputGameID, 1, 100);\n\t\t\t//ImGui::SameLine();\n\t\t\t//if (ImGui::Button(\"Submit##gameID\"))\n\t\t\t//{\n\t\t\t//\tgameID = inputGameID;\n\t\t\t//}\n\n\t\t\t// if pressed any button, gameID or custom changed\n\t\t\tif (gameID != 0 || !custom.empty())\n\t\t\t{\n\t\t\t\tstd::string body;\n\t\t\t\tif (custom.empty())\n\t\t\t\t{\n\t\t\t\t\tbody = R\"({\"queueId\":)\" + std::to_string(gameID) + \"}\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbody = custom;\n\t\t\t\t\tcustom = \"\";\n\t\t\t\t}\n\t\t\t\tif (gameID == DraftPick || gameID == SoloDuo || gameID == Flex || gameID == Quickplay)\n\t\t\t\t{\n\t\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby\", body);\n\n\t\t\t\t\tLCU::Request(\"PUT\", \"/lol-lobby/v1/lobby/members/localMember/position-preferences\",\n\t\t\t\t\t\tR\"({\"firstPreference\":\")\" + firstPosition[S.gameTab.indexFirstRole]\n\t\t\t\t\t\t+ R\"(\",\"secondPreference\":\")\" + secondPosition[S.gameTab.indexSecondRole] + \"\\\"}\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby\", body);\n\t\t\t\t}\n\n\t\t\t\tgameID = 0;\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 7));\n\t\t\tif (const char* labelFirstPosition = firstPosition[S.gameTab.indexFirstRole].c_str(); ImGui::BeginCombo(\n\t\t\t\t\"##comboFirstPosition\", labelFirstPosition, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < firstPosition.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool isSelected = (S.gameTab.indexFirstRole == n);\n\t\t\t\t\tif (ImGui::Selectable(firstPosition[n].c_str(), isSelected))\n\t\t\t\t\t\tS.gameTab.indexFirstRole = n;\n\n\t\t\t\t\tif (isSelected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\t\t\t/*\t\tImGui::SameLine();\n\t\t\t\t\tImGui::Text(\"Primary\");*/\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 7));\n\t\t\tconst char* second_labelPosition = secondPosition[S.gameTab.indexSecondRole].c_str();\n\t\t\tif (ImGui::BeginCombo(\"##comboSecondPosition\", second_labelPosition, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < secondPosition.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool isSelected = (S.gameTab.indexSecondRole == n);\n\t\t\t\t\tif (ImGui::Selectable(secondPosition[n].c_str(), isSelected))\n\t\t\t\t\t\tS.gameTab.indexSecondRole = n;\n\n\t\t\t\t\tif (isSelected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\t\t\t//ImGui::SameLine();\n\t\t\t//ImGui::Text(\"Secondary\");\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Pick roles\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"PUT\", \"/lol-lobby/v1/lobby/members/localMember/position-preferences\",\n\t\t\t\t\tR\"({\"firstPreference\":\")\" + firstPosition[S.gameTab.indexFirstRole]\n\t\t\t\t\t+ R\"(\",\"secondPreference\":\")\" + secondPosition[S.gameTab.indexSecondRole] + \"\\\"}\");\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"If you are already in a lobby you can use this button to pick the roles, or start a new lobby with the buttons above\");\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Change runes\"))\n\t\t\t{\n\t\t\t\tresult = ChangeRunesOpgg();\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tImGui::Checkbox(\"Blue/Red Side notification\", &S.gameTab.sideNotification);\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(3, nullptr, false);\n\t\t\tif (ImGui::Button(\"Start queue\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby/matchmaking/search\");\n\t\t\t}\n\t\t\tImGui::NextColumn();\n\n\t\t\t// if you press this during queue search you wont be able to start the queue again\n\t\t\t// unless you reenter the lobby :)\n\t\t\tif (ImGui::Button(\"Dodge\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\n\t\t\t\t\t\"POST\",\n\t\t\t\t\tR\"(https://127.0.0.1/lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=[\"\",\"teambuilder-draft\",\"quitV2\",\"\"])\",\n\t\t\t\t\t\"\");\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Dodges lobby instantly, you still lose LP, but you don't have to restart the client\");\n\t\t\tImGui::NextColumn();\n\n\t\t\tstatic std::vector<std::string> itemsMultiSearch = {\n\t\t\t\t\"OP.GG\", \"U.GG\", \"PORO.GG\", \"Porofessor.gg\"\n\t\t\t};\n\t\t\tconst char* selectedMultiSearch = itemsMultiSearch[S.gameTab.indexMultiSearch].c_str();\n\n\t\t\tif (ImGui::Button(\"Multi-Search\"))\n\t\t\t{\n\t\t\t\tresult = MultiSearch(itemsMultiSearch[S.gameTab.indexMultiSearch]);\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\t\t\tif (ImGui::BeginCombo(\"##comboMultiSearch\", selectedMultiSearch, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < itemsMultiSearch.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (S.gameTab.indexMultiSearch == n);\n\t\t\t\t\tif (ImGui::Selectable(itemsMultiSearch[n].c_str(), is_selected))\n\t\t\t\t\t\tS.gameTab.indexMultiSearch = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(3, nullptr, false);\n\t\t\tImGui::Checkbox(\"Auto accept\", &S.gameTab.autoAcceptEnabled);\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tstatic std::vector<std::pair<std::string, int>> itemsInvite = { {\"**Default\", 0} };\n\t\t\tstatic size_t itemIdxInvite = 0;\n\t\t\tauto labelInvite = itemsInvite[itemIdxInvite].first.c_str();\n\n\t\t\tif (ImGui::Button(\"Invite to lobby\"))\n\t\t\t{\n\t\t\t\tstd::string getFriends = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friends\");\n\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(getFriends.c_str(), getFriends.c_str() + static_cast<int>(getFriends.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned invitedCount = 0;\n\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (i[\"groupId\"].asInt() != itemsInvite[itemIdxInvite].second)\n\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\tstd::string friendSummId = i[\"summonerId\"].asString();\n\t\t\t\t\t\t\tstd::string inviteBody = \"[{\\\"toSummonerId\\\":\" + friendSummId + \"}]\";\n\t\t\t\t\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby/invitations\", inviteBody);\n\t\t\t\t\t\t\tinvitedCount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult = \"Invited \" + std::to_string(invitedCount) + \" friends to lobby\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(ImGui::CalcTextSize(std::string(15, 'W').c_str(), nullptr, true).x);\n\t\t\tif (ImGui::BeginCombo(\"##comboInvite\", labelInvite, 0))\n\t\t\t{\n\t\t\t\tstd::string getGroups = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friend-groups\");\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(getGroups.c_str(), getGroups.c_str() + static_cast<int>(getGroups.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\titemsInvite.clear();\n\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::pair temp = { i[\"name\"].asString(), i[\"id\"].asInt() };\n\t\t\t\t\t\t\titemsInvite.emplace_back(temp);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstd::ranges::sort(itemsInvite, [](std::pair<std::string, int> a, std::pair<std::string, int> b) { return a.second < b.second; });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (size_t n = 0; n < itemsInvite.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (itemIdxInvite == n);\n\t\t\t\t\tif (ImGui::Selectable(itemsInvite[n].first.c_str(), is_selected))\n\t\t\t\t\t\titemIdxInvite = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tImGui::Text(\"Ultimate Spellbook Force\");\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Jungle\"))\n\t\t\t{\n\t\t\t\tLCU::Request(\"PATCH\", \"/lol-champ-select/v1/session/my-selection\", \"{\\\"spell1Id\\\":4,\\\"spell2Id\\\":55}\");\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Lane\"))\n\t\t\t{\n\t\t\t\tLCU::Request(\"PATCH\", \"/lol-champ-select/v1/session/my-selection\", \"{\\\"spell1Id\\\":4,\\\"spell2Id\\\":54}\");\n\t\t\t}\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\t//ImGui::Columns(2, 0, false);\n\n\t\t\tImGui::Text(\"Instant message:\");\n\t\t\tImGui::SameLine();\n\t\t\tstatic char bufInstantMessage[500];\n\t\t\tstd::ranges::copy(S.gameTab.instantMessage, bufInstantMessage);\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\t\t\tImGui::InputText(\"##inputInstantMessage\", bufInstantMessage, IM_ARRAYSIZE(bufInstantMessage));\n\t\t\tS.gameTab.instantMessage = bufInstantMessage;\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 7));\n\t\t\tImGui::SliderInt(\"Delay##sliderInstantMessageDelay\", &S.gameTab.instantMessageDelay, 0, 10000, \"%d ms\");\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 10));\n\t\t\tImGui::SliderInt(\"Time(s)##sliderInstantMessageTimes\", &S.gameTab.instantMessageTimes, 1, 10, \"%d\");\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 7));\n\t\t\tImGui::SliderInt(\"Delay between##sliderInstantMessageDelayTimes\", &S.gameTab.instantMessageDelayTimes, 0, 4000, \"%d ms\");\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic bool isStillBeingFetched = true;\n\t\t\tif (!champSkins.empty())\n\t\t\t\tisStillBeingFetched = false;\n\n\t\t\tstatic ImGui::ComboAutoSelectData instalockComboData;\n\n\t\t\tif (onOpen)\n\t\t\t{\n\t\t\t\tstd::vector<std::pair<int, std::string>> instalockChamps = GetInstalockChamps();\n\n\t\t\t\tif (!instalockChamps.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> instalockChampsNames;\n\t\t\t\t\tinstalockChampsNames.reserve(instalockChamps.size() + 1);\n\t\t\t\t\tinstalockChampsNames.emplace_back(\"Random\");\n\n\t\t\t\t\tif (S.gameTab.instalockId == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ranges::copy(\"Random\", instalockComboData.input);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string selectedChamp = ChampIdToName(S.gameTab.instalockId);\n\t\t\t\t\t\tstd::ranges::copy(selectedChamp, instalockComboData.input);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (size_t i = 0; i < instalockChamps.size(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tinstalockChampsNames.emplace_back(instalockChamps[i].second);\n\t\t\t\t\t\tif (instalockComboData.input == instalockChamps[i].second)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinstalockComboData.index = i + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tinstalockComboData.items = instalockChampsNames;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::Checkbox(\"Instalock\", &S.gameTab.instalockEnabled);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\t\t\tif (ImGui::ComboAutoSelect(\"##comboInstalock\", instalockComboData))\n\t\t\t{\n\t\t\t\tif (instalockComboData.index != -1)\n\t\t\t\t{\n\t\t\t\t\tif (std::string(instalockComboData.input) == \"Random\")\n\t\t\t\t\t{\n\t\t\t\t\t\tS.gameTab.instalockId = -1;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (instalockComboData.input == name)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tS.gameTab.instalockId = key;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\n\t\t\tImGui::SliderInt(\"Delay##sliderInstalockDelay\", &S.gameTab.instalockDelay, 0, 10000, \"%d ms\");\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::Checkbox(\"Dodge on champion ban\", &S.gameTab.dodgeOnBan);\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Ignores backup pick\");\n\n\t\t\tstatic std::string chosenBackup = \"Backup pick \\t\\t\\tChosen: \" + Misc::ChampIdToName(S.gameTab.backupId) + \"###AnimatedBackup\";\n\t\t\tstatic int lastBackupId = 0;\n\t\t\tif ((lastBackupId != S.gameTab.backupId) && !isStillBeingFetched)\n\t\t\t{\n\t\t\t\tlastBackupId = S.gameTab.backupId;\n\t\t\t\tchosenBackup = \"Backup pick \\t\\t\\tChosen: \" + Misc::ChampIdToName(S.gameTab.backupId) + \"###AnimatedBackup\";\n\t\t\t}\n\t\t\tif (ImGui::CollapsingHeader(chosenBackup.c_str()))\n\t\t\t{\n\t\t\t\tImGui::Text(\"None\");\n\t\t\t\tImGui::SameLine();\n\t\t\t\tImGui::RadioButton(\"##noneBackupPick\", &S.gameTab.backupId, 0);\n\t\t\t\tstd::vector<std::pair<int, std::string>> instalockChamps = GetInstalockChamps();\n\t\t\t\tfor (const auto& [fst, snd] : instalockChamps)\n\t\t\t\t{\n\t\t\t\t\tchar bufchamp[128];\n\t\t\t\t\tsprintf_s(bufchamp, \"##Select %s\", snd.c_str());\n\t\t\t\t\tImGui::Text(\"%s\", snd.c_str());\n\t\t\t\t\tImGui::SameLine();\n\t\t\t\t\tImGui::RadioButton(bufchamp, &S.gameTab.backupId, fst);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::Checkbox(\"Auto ban\", &S.gameTab.autoBanEnabled);\n\t\t\tImGui::SameLine();\n\n\t\t\tstatic ImGui::ComboAutoSelectData autobanComboData;\n\t\t\tif (onOpen)\n\t\t\t{\n\t\t\t\tstd::vector<std::string> autobanChampsNames;\n\t\t\t\tif (!champSkins.empty())\n\t\t\t\t{\n\t\t\t\t\tautobanChampsNames.reserve(champSkins.size() + 1);\n\t\t\t\t\tautobanChampsNames.emplace_back(\"None\");\n\n\t\t\t\t\tif (S.gameTab.autoBanId == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ranges::copy(\"None\", autobanComboData.input);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string selectedChamp = ChampIdToName(S.gameTab.autoBanId);\n\t\t\t\t\t\tstd::ranges::copy(selectedChamp, autobanComboData.input);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (size_t i = 0; i < champSkins.size(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tautobanChampsNames.emplace_back(champSkins[i].name);\n\n\t\t\t\t\t\tif (autobanComboData.input == champSkins[i].name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tautobanComboData.index = i + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tautobanComboData.items = autobanChampsNames;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\t\t\tif (ImGui::ComboAutoSelect(\"##comboAutoban\", autobanComboData))\n\t\t\t{\n\t\t\t\tif (autobanComboData.index != -1)\n\t\t\t\t{\n\t\t\t\t\tif (std::string(autobanComboData.input) == \"None\")\n\t\t\t\t\t{\n\t\t\t\t\t\tS.gameTab.autoBanId = -1;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (autobanComboData.input == name)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tS.gameTab.autoBanId = key;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 6));\n\t\t\tImGui::SliderInt(\"Delay##sliderautoBanDelay\", &S.gameTab.autoBanDelay, 0, 10000, \"%d ms\");\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::Checkbox(\"Instant Mute\", &S.gameTab.instantMute);\n\n\t\t\t/*\n\t\t\t\tFree ARAM Boost exploit\n\t\t\t\tFun fact: I've reported this to Riot on 23rd August 2021 together with the refund exploit\n\t\t\t\tI've got a response that my report is a duplicate (it wasn't, I found the exploits)\n\t\t\t\tAlmost 2 years later, both of them are still not fixed.\n\t\t\t*/\n\n\t\t\tImGui::SeparatorText(\"Free ARAM Boost\");\n\n\t\t\tstatic std::string storeToken; // EntityAssignedButNoRead\n\t\t\tstatic cpr::Header storeHeader;\n\t\t\tstatic std::string accountId;\n\t\t\tstatic std::string boosted;\n\t\t\tstatic int ownedRP;\n\t\t\tif (ImGui::Button(\"Is boost available for this account?\"))\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\n\t\t\t\t// get rp amount\n\t\t\t\tstd::string getWallet = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v1/wallet/RP\");\n\t\t\t\tif (reader->parse(getWallet.c_str(), getWallet.c_str() + static_cast<int>(getWallet.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\townedRP = root[\"RP\"].asInt();\n\t\t\t\t}\n\n\t\t\t\t// get accountId\n\t\t\t\tstd::string getSession = LCU::Request(\"GET\", \"https://127.0.0.1/lol-login/v1/session\");\n\t\t\t\tif (reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\taccountId = root[\"accountId\"].asString();\n\t\t\t\t}\n\n\t\t\t\tif (!CheckJWT(accountId) && ownedRP < 95)\n\t\t\t\t{\n\t\t\t\t\tint timeleft = 0;\n\t\t\t\t\tstd::string temp = GetOldJWT(accountId, timeleft);\n\t\t\t\t\ttimeleft = timeleft + 60 * 60 * 24 - time(nullptr);\n\t\t\t\t\tint minutes = timeleft / 60 - 60 * (timeleft / (60 * 60));\n\t\t\t\t\tboosted = \"Boost available, time left on this account: \" + std::to_string(timeleft / (60 * 60)) + \":\" + std::to_string(minutes);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// get owned champions\n\t\t\t\t\tstd::vector<int> ownedChampions;\n\t\t\t\t\tstd::string getChampions = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v2/inventory/CHAMPION\");\n\t\t\t\t\tif (reader->parse(getChampions.c_str(), getChampions.c_str() + static_cast<int>(getChampions.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto obj : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (obj[\"ownershipType\"].asString() == \"OWNED\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\townedChampions.emplace_back(obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::vector<std::pair<int, int>> champsToBuy; // price, id\n\t\t\t\t\tstd::string getCatalog = LCU::Request(\"GET\", \"https://127.0.0.1/lol-store/v1/catalog\");\n\t\t\t\t\tif (reader->parse(getCatalog.c_str(), getCatalog.c_str() + static_cast<int>(getCatalog.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto obj : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (obj[\"inventoryType\"].asString() == \"CHAMPION\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (obj[\"sale\"].empty() == true)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < obj[\"prices\"].size(); i++)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (auto price = obj[\"prices\"][i]; price[\"currency\"].asString() == \"RP\")\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tchampsToBuy.emplace_back(price[\"cost\"].asInt(), obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < obj[\"sale\"][\"prices\"].size(); i++)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (auto sale = obj[\"sale\"][\"prices\"][i]; sale[\"currency\"].asString() == \"RP\")\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tchampsToBuy.emplace_back(sale[\"cost\"].asInt(), obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tint idToBuy = 0;\n\t\t\t\t\tint priceToBuy = 0;\n\n\t\t\t\t\tfor (auto [fst, snd] : champsToBuy)\n\t\t\t\t\t{\n\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\tfor (int id : ownedChampions)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (snd == id)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (ownedRP - fst > 0 && ownedRP - fst < 95)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpriceToBuy = fst;\n\t\t\t\t\t\t\t\tidToBuy = snd;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (idToBuy != 0 && priceToBuy != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tboosted = \"Boost is available for this account\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tboosted = \"Boost IS NOT available for this account\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Free ARAM/ARURF boost\"))\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\n\t\t\t\t// get rp ammount\n\t\t\t\tstd::string getWallet = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v1/wallet/RP\");\n\t\t\t\tif (reader->parse(getWallet.c_str(), getWallet.c_str() + static_cast<int>(getWallet.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\townedRP = root[\"RP\"].asInt();\n\t\t\t\t}\n\n\t\t\t\t// get accountId\n\t\t\t\tstd::string getSession = LCU::Request(\"GET\", \"https://127.0.0.1/lol-login/v1/session\");\n\t\t\t\tif (reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\taccountId = root[\"accountId\"].asString();\n\t\t\t\t}\n\n\t\t\t\tbool bNeedNewJwt = true;\n\t\t\t\tif (!CheckJWT(accountId))\n\t\t\t\t{\n\t\t\t\t\tbNeedNewJwt = false;\n\t\t\t\t\tif (ownedRP >= 95)\n\t\t\t\t\t\tbNeedNewJwt = true;\n\t\t\t\t}\n\n\t\t\t\t// get owned champions\n\t\t\t\tstd::vector<int> ownedChampions;\n\t\t\t\tstd::string getChampions = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v2/inventory/CHAMPION\");\n\t\t\t\tif (reader->parse(getChampions.c_str(), getChampions.c_str() + static_cast<int>(getChampions.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto obj : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (obj[\"ownershipType\"].asString() == \"OWNED\")\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\townedChampions.emplace_back(obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstd::vector<std::pair<int, int>> champsToBuy; // price, id\n\t\t\t\tstd::string getCatalog = LCU::Request(\"GET\", \"https://127.0.0.1/lol-store/v1/catalog\");\n\t\t\t\tif (reader->parse(getCatalog.c_str(), getCatalog.c_str() + static_cast<int>(getCatalog.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto obj : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (obj[\"inventoryType\"].asString() == \"CHAMPION\")\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (obj[\"sale\"].empty() == true)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < obj[\"prices\"].size(); i++)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (auto price = obj[\"prices\"][i]; price[\"currency\"].asString() == \"RP\")\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tchampsToBuy.emplace_back(price[\"cost\"].asInt(), obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < obj[\"sale\"][\"prices\"].size(); i++)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (auto sale = obj[\"sale\"][\"prices\"][i]; sale[\"currency\"].asString() == \"RP\")\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tchampsToBuy.emplace_back(sale[\"cost\"].asInt(), obj[\"itemId\"].asInt());\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tint idToBuy = 0;\n\t\t\t\tint priceToBuy = 0;\n\n\t\t\t\tfor (auto [fst, snd] : champsToBuy)\n\t\t\t\t{\n\t\t\t\t\tbool found = false;\n\t\t\t\t\tfor (int id : ownedChampions)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (snd == id)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!found)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ownedRP - fst > 0 && ownedRP - fst < 95)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpriceToBuy = fst;\n\t\t\t\t\t\t\tidToBuy = snd;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ((idToBuy != 0 && priceToBuy != 0) || !bNeedNewJwt)\n\t\t\t\t{\n\t\t\t\t\tstd::string getStoreUrl = LCU::Request(\"GET\", \"https://127.0.0.1/lol-store/v1/getStoreUrl\");\n\t\t\t\t\tstd::erase(getStoreUrl, '\"');\n\n\t\t\t\t\tJson::CharReaderBuilder builder2;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader2(builder2.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err2;\n\t\t\t\t\tJson::Value root2;\n\n\t\t\t\t\t// get signedWalletJwt\n\t\t\t\t\tstd::string signedWalletJwt = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v1/signedWallet/RP\");\n\t\t\t\t\tif (reader2->parse(signedWalletJwt.c_str(), signedWalletJwt.c_str() + static_cast<int>(signedWalletJwt.length()), &root2, &err2))\n\t\t\t\t\t{\n\t\t\t\t\t\tsignedWalletJwt = root2[\"RP\"].asString();\n\t\t\t\t\t\tif (bNeedNewJwt)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSaveJWT(accountId, signedWalletJwt, time(nullptr));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint timeleft = 0;\n\t\t\t\t\t\t\tsignedWalletJwt = GetOldJWT(accountId, timeleft);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tJson::CharReaderBuilder builder3;\n\t\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader3(builder3.newCharReader());\n\t\t\t\t\t\tJSONCPP_STRING err3;\n\t\t\t\t\t\tJson::Value root3;\n\n\t\t\t\t\t\t// get Bearer token for store\n\t\t\t\t\t\tstd::string authorizations = LCU::Request(\"GET\", \"https://127.0.0.1/lol-rso-auth/v1/authorization/access-token\");\n\t\t\t\t\t\tif (reader3->parse(authorizations.c_str(), authorizations.c_str() + static_cast<int>(authorizations.length()), &root3, &err3))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstoreToken = root3[\"token\"].asString();\n\t\t\t\t\t\t\tstoreHeader = Utils::StringToHeader(LCU::GetStoreHeader());\n\t\t\t\t\t\t\tif (bNeedNewJwt)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// buy a champion\n\t\t\t\t\t\t\t\tstd::string purchaseBody = R\"({\"accountId\":)\" + accountId + R\"(,\"items\":[{\"inventoryType\":\"CHAMPION\",\"itemId\":)\" +\n\t\t\t\t\t\t\t\t\tstd::to_string(idToBuy)\n\t\t\t\t\t\t\t\t\t+ R\"(,\"ipCost\":null,\"rpCost\":)\" + std::to_string(priceToBuy) + R\"(,\"quantity\":1}]})\";\n\t\t\t\t\t\t\t\tstd::string purchaseUrl = getStoreUrl + \"/storefront/v3/purchase?language=en_US\";\n\t\t\t\t\t\t\t\tstd::string purchase = cpr::Post(cpr::Url{ purchaseUrl }, cpr::Body{ purchaseBody }, cpr::Header{ storeHeader }).text;\n\t\t\t\t\t\t\t\tboosted = \"Bought \" + ChampIdToName(idToBuy) + \" - dont play this champion, or you wont be able to refund RP\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::seconds(1));\n\n\t\t\t\t\t\t\t// boost with signedWalletJwt\n\t\t\t\t\t\t\tstd::string boostUrl =\n\t\t\t\t\t\t\t\tR\"(https://127.0.0.1/lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=[\"\",\"teambuilder-draft\",\"activateBattleBoostV1\",\"{\\\"signedWalletJwt\\\":\\\")\"\n\t\t\t\t\t\t\t\t+ signedWalletJwt + R\"(\\\"}\"])\";\n\t\t\t\t\t\t\tLCU::Request(\"POST\", boostUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tboosted = \"Ineligible for boost on this account\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Refund RP\"))\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\n\t\t\t\t// get accountId\n\t\t\t\tstd::string getSession = LCU::Request(\"GET\", \"https://127.0.0.1/lol-login/v1/session\");\n\t\t\t\tif (reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\taccountId = root[\"accountId\"].asString();\n\t\t\t\t}\n\n\t\t\t\tstd::string getStoreUrl = LCU::Request(\"GET\", \"https://127.0.0.1/lol-store/v1/getStoreUrl\");\n\t\t\t\tstd::erase(getStoreUrl, '\"');\n\n\t\t\t\tstd::string authorizations = LCU::Request(\"GET\", \"https://127.0.0.1/lol-rso-auth/v1/authorization/access-token\");\n\t\t\t\tif (reader->parse(authorizations.c_str(), authorizations.c_str() + static_cast<int>(authorizations.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tstoreToken = root[\"token\"].asString();\n\t\t\t\t\tstoreHeader = Utils::StringToHeader(LCU::GetStoreHeader());\n\t\t\t\t}\n\n\t\t\t\tstd::string historyUrl = getStoreUrl + \"/storefront/v3/history/purchase?language=en_US\";\n\t\t\t\tstd::string getHistory = cpr::Get(cpr::Url{ historyUrl }, cpr::Header{ storeHeader }).text;\n\t\t\t\tif (reader->parse(getHistory.c_str(), getHistory.c_str() + static_cast<int>(getHistory.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root[\"transactions\"].isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < root[\"transactions\"].size(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (auto transaction = root[\"transactions\"][i]; transaction[\"refundable\"].asBool() == true)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (transaction[\"inventoryType\"].asString() == \"CHAMPION\")\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (transaction[\"currencyType\"].asString() == \"RP\")\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (transaction[\"requiresToken\"].asBool() == false)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tstd::string refundUrl = getStoreUrl + \"/storefront/v3/refund\";\n\t\t\t\t\t\t\t\t\t\t\tstd::string refundBody = R\"({\"accountId\":)\" + accountId + R\"(,\"transactionId\":\")\" + transaction[\n\t\t\t\t\t\t\t\t\t\t\t\t\"transactionId\"].asString() + R\"(\",\"inventoryType\":\"CHAMPION\",\"language\":\"en_US\"})\";\n\t\t\t\t\t\t\t\t\t\t\t\tPost(cpr::Url{ refundUrl }, cpr::Body{ refundBody }, cpr::Header{ storeHeader });\n\t\t\t\t\t\t\t\t\t\t\t\tboosted = \"Refunded\";\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Instructions:\\n\"\n\t\t\t\t\"You have to wait at least 1 hour after finishing your last game, otherwise the RP you used for boost will get consumed\\n\"\n\t\t\t\t\"The longer you wait, the better. On a single token you can boost unlimited amount of times in 24h\\n\"\n\t\t\t\t\"The exploit stores your RP, buys a champion with RP so you're left with <95 and then boosts using the stored RP\\n\"\n\t\t\t\t\"Don't play with the champion the boost bought, or you wont be able to get your RP back\\n\");\n\n\t\t\tImGui::TextWrapped(boosted.c_str());\n\n\t\t\t//ImGui::Separator();\n\n\t\t\t// Patched :(\n\t\t\t//if (ImGui::Button(\"Free ARAM/ARURF boost\"))\n\t\t\t//{\n\t\t\t//\tstd::string wallet = http->Request(\"GET\", \"https://127.0.0.1/lol-inventory/v1/wallet/RP\", \"\", auth->leagueHeader, \"\", \"\", auth->leaguePort);\n\t\t\t//\tJson::CharReaderBuilder builder;\n\t\t\t//\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t//\tJSONCPP_STRING err;\n\t\t\t//\tJson::Value root;\n\t\t\t//\tif (!reader->parse(wallet.c_str(), wallet.c_str() + static_cast<int>(wallet.length()), &root, &err))\n\t\t\t//\t\tresult = wallet;\n\t\t\t//\telse\n\t\t\t//\t{\n\t\t\t//\t\tif (unsigned RP = root[\"RP\"].asUInt(); RP < 95)\n\t\t\t//\t\t{\n\t\t\t//\t\t\tresult = http->Request(\"POST\", R\"(https://127.0.0.1/lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=[\"\",\"teambuilder-draft\",\"activateBattleBoostV1\",\"\"])\", \"\", auth->leagueHeader, \"\", \"\", auth->leaguePort);\n\t\t\t//\t\t}\n\t\t\t//\t\telse\n\t\t\t//\t\t{\n\t\t\t//\t\t\tMessageBoxA(0, \"You have enough RP\", \"It's not possible to grant you a free skin boost\", 0);\n\t\t\t//\t\t}\n\t\t\t//\t}\n\t\t\t//}\n\t\t\t//ImGui::SameLine();\n\t\t\t//Misc::HelpMarker(\"Works only when you don't have enough RP for boost\");\n\n\t\t\tstatic Json::StreamWriterBuilder wBuilder;\n\t\t\tstatic std::string sResultJson;\n\t\t\tstatic char* cResultJson;\n\n\t\t\tif (!result.empty())\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (!reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t\t\t\tsResultJson = result;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsResultJson = Json::writeString(wBuilder, root);\n\t\t\t\t}\n\t\t\t\tresult = \"\";\n\t\t\t}\n\n\t\t\tif (!sResultJson.empty())\n\t\t\t{\n\t\t\t\tcResultJson = sResultJson.data();\n\t\t\t\tImGui::InputTextMultiline(\"##gameResult\", cResultJson, sResultJson.size() + 1, ImVec2(600, 300));\n\t\t\t}\n\n\t\t\tif (onOpen)\n\t\t\t\tonOpen = false;\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tonOpen = true;\n\t\t}\n\t}\n\n\tstatic std::vector<std::pair<int, std::string>> GetInstalockChamps()\n\t{\n\t\tstd::vector<std::pair<int, std::string>> temp;\n\n\t\tstd::string result = LCU::Request(\"GET\", \"https://127.0.0.1/lol-champions/v1/owned-champions-minimal\");\n\t\tJson::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t{\n\t\t\tif (root.isArray())\n\t\t\t{\n\t\t\t\tfor (auto& i : root)\n\t\t\t\t{\n\t\t\t\t\tif (i[\"freeToPlay\"].asBool() == true || i[\"ownership\"][\"owned\"].asBool() == true ||\n\t\t\t\t\t\t(i[\"ownership\"].isMember(\"xboxGPReward\") && i[\"ownership\"][\"xboxGPReward\"].asBool() == true))\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string loadScreenPath = i[\"baseLoadScreenPath\"].asString();\n\t\t\t\t\t\tsize_t nameStart = loadScreenPath.find(\"ASSETS/Characters/\") + strlen(\"ASSETS/Characters/\");\n\t\t\t\t\t\tstd::string champName = loadScreenPath.substr(nameStart, loadScreenPath.find('/', nameStart) - nameStart);\n\n\t\t\t\t\t\tstd::pair champ = { i[\"id\"].asInt(), champName };\n\t\t\t\t\t\ttemp.emplace_back(champ);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tstd::ranges::sort(temp, [](std::pair<int, std::string> a, std::pair<int, std::string> b) { return a.second < b.second; });\n\t\treturn temp;\n\t}\n\n\tstatic void InstantMessage(const bool instantMute = false, const bool sideNotification = false)\n\t{\n\t\tauto start = std::chrono::system_clock::now();\n\t\twhile (true)\n\t\t{\n\t\t\tauto now = std::chrono::system_clock::now();\n\t\t\tstd::chrono::duration<double> diff = now - start;\n\t\t\tif (diff.count() > 10) // took 10 seconds and still didn't connect to chat\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t\tJson::Value root;\n\t\t\tJson::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING err;\n\n\t\t\tLCU::SetCurrentClientRiotInfo();\n\t\t\tstd::string getChat = cpr::Get(cpr::Url{ std::format(\"https://127.0.0.1:{}/chat/v5/participants\", LCU::riot.port) },\n\t\t\t\tcpr::Header{ Utils::StringToHeader(LCU::riot.header) }, cpr::VerifySsl{ false }).text;\n\t\t\tif (!reader->parse(getChat.c_str(), getChat.c_str() + static_cast<int>(getChat.length()), &root, &err))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst auto& participantsArr = root[\"participants\"];\n\t\t\tif (!participantsArr.isArray())\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (participantsArr.size() <= 1)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tstd::string cid = \"\";\n\t\t\tfor (auto& i : participantsArr)\n\t\t\t{\n\t\t\t\tif (i[\"cid\"].asString().contains(\"champ-select\"))\n\t\t\t\t{\n\t\t\t\t\tcid = i[\"cid\"].asString();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (cid == \"\")\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (instantMute || sideNotification)\n\t\t\t{\n\t\t\t\tstd::string champSelect = LCU::Request(\"GET\", \"/lol-champ-select/v1/session\");\n\t\t\t\tJson::Value rootCSelect;\n\t\t\t\tif (!champSelect.empty() && champSelect.find(\"RPC_ERROR\") == std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tif (reader->parse(champSelect.c_str(), champSelect.c_str() + static_cast<int>(champSelect.length()), &rootCSelect, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (instantMute)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint localPlayerCellId = rootCSelect[\"localPlayerCellId\"].asInt();\n\t\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < rootCSelect[\"myTeam\"].size(); i++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tJson::Value player = rootCSelect[\"myTeam\"][i];\n\t\t\t\t\t\t\t\tif (player[\"cellId\"].asInt() == localPlayerCellId)\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\tLCU::Request(\"POST\", \"/lol-champ-select/v1/toggle-player-muted\",\n\t\t\t\t\t\t\t\t\tstd::format(R\"({{\"summonerId\":{0},\"puuid\":\"{1}\",\"obfuscatedSummonerId\":{2},\"obfuscatedPuuid\":\"{3}\"}})\",\n\t\t\t\t\t\t\t\t\t\tplayer[\"summonerId\"].asString(), player[\"puuid\"].asString(),\n\t\t\t\t\t\t\t\t\t\tplayer[\"obfuscatedSummonerId\"].asString(),\n\t\t\t\t\t\t\t\t\t\tplayer[\"obfuscatedPuuid\"].asString()));\n\n\t\t\t\t\t\t\t\t/*\tLCU::Request(\"POST\", \"/telemetry/v1/events/general_metrics_number\",\n\t\t\t\t\t\t\t\t\t\tR\"({\"eventName\":\"champ_select_toggle_player_muted_clicked\",\"value\":\"0\",\"spec\":\"high\",\"isLowSpecModeOn\":\"false\"})\");\n\n\t\t\t\t\t\t\t\t\tLCU::Request(\"POST\", std::format(\"/lol-chat/v1/conversations/{}/messages\", cid),\n\t\t\t\t\t\t\t\t\t\tstd::format(\"{{\\\"body\\\":\\\"{} is muted.\\\",\\\"type\\\":\\\"celebration\\\"}}\", \"player\"));\n\t\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sideNotification)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (rootCSelect[\"myTeam\"].isArray() && !rootCSelect[\"myTeam\"].empty())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::string notification = \"You are on the \";\n\t\t\t\t\t\t\t\tif (rootCSelect[\"myTeam\"][0][\"team\"].asInt() == 1)\n\t\t\t\t\t\t\t\t\tnotification += \"Blue Side\";\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tnotification += \"Red Side\";\n\t\t\t\t\t\t\t\tLCU::Request(\"POST\", std::format(\"/lol-chat/v1/conversations/{}/messages\", cid),\n\t\t\t\t\t\t\t\t\tR\"({\"body\":\")\" + notification + R\"(\",\"type\":\"celebration\"})\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (S.gameTab.instantMessage.empty())\n\t\t\t\treturn;\n\n\t\t\tconst std::string request = \"https://127.0.0.1/lol-chat/v1/conversations/\" + cid + \"/messages\";\n\t\t\tconst std::string body = R\"({\"type\":\"chat\", \"body\":\")\" + std::string(S.gameTab.instantMessage) + R\"(\"})\";\n\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(S.gameTab.instantMessageDelay));\n\n\t\t\tnow = std::chrono::system_clock::now();\n\t\t\tint numOfSent = 0;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tfor (; numOfSent < S.gameTab.instantMessageTimes; numOfSent++)\n\t\t\t\t{\n\t\t\t\t\tif (std::string error = LCU::Request(\"POST\", request, body); error.find(\"errorCode\") != std::string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(S.gameTab.instantMessageDelayTimes));\n\t\t\t\t}\n\n\t\t\t\tif (numOfSent >= S.gameTab.instantMessageTimes)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdiff = now - start;\n\t\t\t\tif (diff.count() > 10) // took 10 seconds and still not all messages sent\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void AutoAccept()\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\n\t\t\tif (FindWindowA(\"RiotWindowClass\", \"League of Legends (TM) Client\"))\n\t\t\t{\n\t\t\t\t// game is running, auto accept is not needed\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!FindWindowA(\"RCLIENT\", \"League of Legends\"))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (S.gameTab.autoAcceptEnabled || (S.gameTab.autoBanEnabled && S.gameTab.autoBanId) ||\n\t\t\t\t(S.gameTab.dodgeOnBan && S.gameTab.instalockEnabled) ||\n\t\t\t\t(S.gameTab.instalockEnabled && S.gameTab.instalockId) ||\n\t\t\t\t!S.gameTab.instantMessage.empty())\n\t\t\t{\n\t\t\t\tJson::Value rootSearch;\n\t\t\t\tJson::Value rootChampSelect;\n\t\t\t\tJson::Value rootSession;\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\n\t\t\t\tcpr::Session session;\n\t\t\t\tsession.SetVerifySsl(false);\n\t\t\t\tsession.SetHeader(Utils::StringToHeader(LCU::league.header));\n\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-lobby/v2/lobby/matchmaking/search-state\", LCU::league.port));\n\n\t\t\t\tstd::string getSearchState = session.Get().text;\n\t\t\t\tif (!reader->parse(getSearchState.c_str(), getSearchState.c_str() + static_cast<int>(getSearchState.length()), &rootSearch, &err))\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tstatic bool onChampSelect = true; //false when in champ select\n\t\t\t\tstatic int useBackupId = 0;\n\t\t\t\tstatic bool isPicked = false;\n\n\t\t\t\tif (rootSearch[\"searchState\"].asString() != \"Found\") // not found, not in champ select\n\t\t\t\t{\n\t\t\t\t\tonChampSelect = true;\n\t\t\t\t\tuseBackupId = 0;\n\t\t\t\t\tisPicked = false;\n\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-champ-select/v1/session\", LCU::league.port));\n\t\t\t\tstd::string getChampSelect = session.Get().text;\n\t\t\t\tif (getChampSelect.find(\"RPC_ERROR\") != std::string::npos) // game found but champ select error means queue pop\n\t\t\t\t{\n\t\t\t\t\tonChampSelect = true;\n\t\t\t\t\tuseBackupId = 0;\n\t\t\t\t\tisPicked = false;\n\t\t\t\t\tif (S.gameTab.autoAcceptEnabled)\n\t\t\t\t\t{\n\t\t\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-matchmaking/v1/ready-check/accept\", LCU::league.port));\n\t\t\t\t\t\tsession.SetBody(\"\");\n\t\t\t\t\t\tsession.Post();\n\t\t\t\t\t}\n\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\t\t}\n\t\t\t\telse // in champ select\n\t\t\t\t{\n\t\t\t\t\tif (!reader->parse(getChampSelect.c_str(), getChampSelect.c_str() + static_cast<int>(getChampSelect.length()), &rootChampSelect,\n\t\t\t\t\t\t&err))\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (onChampSelect)\n\t\t\t\t\t{\n\t\t\t\t\t\tonChampSelect = false;\n\n\t\t\t\t\t\tif (!S.gameTab.instantMessage.empty() || S.gameTab.instantMute || S.gameTab.sideNotification)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::thread instantMessageThread(&GameTab::InstantMessage, S.gameTab.instantMute, S.gameTab.sideNotification);\n\t\t\t\t\t\t\tinstantMessageThread.detach();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((S.gameTab.instalockEnabled || S.gameTab.autoBanId) && !isPicked)\n\t\t\t\t\t{\n\t\t\t\t\t\t// get own summid\n\t\t\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-login/v1/session\", LCU::league.port));\n\t\t\t\t\t\tstd::string getSession = session.Get().text;\n\t\t\t\t\t\tif (!reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &rootSession, &err))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst int cellId = rootChampSelect[\"localPlayerCellId\"].asInt();\n\t\t\t\t\t\tfor (Json::Value::ArrayIndex j = 0; j < rootChampSelect[\"actions\"].size(); j++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto actions = rootChampSelect[\"actions\"][j];\n\t\t\t\t\t\t\tif (!actions.isArray())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor (auto& action : actions)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// search for own actions\n\t\t\t\t\t\t\t\tif (action[\"actorCellId\"].asInt() == cellId)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (std::string actionType = action[\"type\"].asString(); actionType == \"pick\"\n\t\t\t\t\t\t\t\t\t\t&& S.gameTab.instalockId && S.gameTab.instalockEnabled)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// if haven't picked yet\n\t\t\t\t\t\t\t\t\t\tif (action[\"completed\"].asBool() == false)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (!isPicked)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(S.gameTab.instalockDelay));\n\n\t\t\t\t\t\t\t\t\t\t\t\tint currentPick = S.gameTab.instalockId;\n\t\t\t\t\t\t\t\t\t\t\t\tif (useBackupId)\n\t\t\t\t\t\t\t\t\t\t\t\t\tcurrentPick = useBackupId;\n\n\t\t\t\t\t\t\t\t\t\t\t\tif (S.gameTab.instalockId == -1)\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tstd::vector<std::pair<int, std::string>> instalockChamps = GetInstalockChamps();\n\t\t\t\t\t\t\t\t\t\t\t\t\tcurrentPick = instalockChamps[Utils::RandomInt(0, instalockChamps.size() - 1)].first;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-champ-select/v1/session/actions/{}\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tLCU::league.port,\n\t\t\t\t\t\t\t\t\t\t\t\t\taction[\"id\"].asString()));\n\t\t\t\t\t\t\t\t\t\t\t\tsession.SetBody(R\"({\"completed\":true,\"championId\":)\" + std::to_string(currentPick) + \"}\");\n\t\t\t\t\t\t\t\t\t\t\t\tsession.Patch();\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tisPicked = true;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (actionType == \"ban\" && S.gameTab.autoBanId && S.gameTab.autoBanEnabled)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (action[\"completed\"].asBool() == false)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(S.gameTab.autoBanDelay));\n\n\t\t\t\t\t\t\t\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-champ-select/v1/session/actions/{}\",\n\t\t\t\t\t\t\t\t\t\t\t\tLCU::league.port,\n\t\t\t\t\t\t\t\t\t\t\t\taction[\"id\"].asString()));\n\t\t\t\t\t\t\t\t\t\t\tsession.SetBody(R\"({\"completed\":true,\"championId\":)\" + std::to_string(S.gameTab.autoBanId) + \"}\");\n\t\t\t\t\t\t\t\t\t\t\tsession.Patch();\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// action that isn't our player, if dodge on ban enabled or backup pick\n\t\t\t\t\t\t\t\telse if ((S.gameTab.dodgeOnBan || S.gameTab.backupId) && S.gameTab.instalockEnabled\n\t\t\t\t\t\t\t\t\t&& S.gameTab.instalockId && (S.gameTab.instalockId != -1))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (isPicked)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tif (action[\"actorCellId\"].asInt() == cellId)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t\tif (action[\"type\"].asString() == \"ban\" && action[\"completed\"].asBool() == true)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (action[\"championId\"].asInt() == S.gameTab.instalockId)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (S.gameTab.dodgeOnBan)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tsession.SetUrl(\n\t\t\t\t\t\t\t\t\t\t\t\t\tstd::format(\"https://127.0.0.1:{}\", LCU::league.port) +\n\t\t\t\t\t\t\t\t\t\t\t\t\tR\"(/lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=[\"\",\"teambuilder-draft\",\"quitV2\",\"\"])\");\n\t\t\t\t\t\t\t\t\t\t\t\tsession.SetBody(\"\");\n\t\t\t\t\t\t\t\t\t\t\t\tsession.Post();\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse if (S.gameTab.backupId)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tuseBackupId = S.gameTab.backupId;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (action[\"type\"].asString() == \"pick\" && action[\"completed\"].asBool() == true)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (S.gameTab.backupId && (action[\"championId\"].asInt() == S.gameTab.instalockId))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tuseBackupId = S.gameTab.backupId;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse // instalock or autoban not enabled, we do nothing in champ select\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic std::string MultiSearch(const std::string& website)\n\t{\n\t\tstd::string names;\n\t\tstd::string champSelect = LCU::Request(\"GET\", \"https://127.0.0.1/lol-champ-select/v1/session\");\n\t\tif (!champSelect.empty() && champSelect.find(\"RPC_ERROR\") == std::string::npos)\n\t\t{\n\t\t\tJson::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING err;\n\t\t\tJson::Value rootRegion;\n\t\t\tJson::Value rootCSelect;\n\t\t\tJson::Value rootSummoner;\n\t\t\tJson::Value rootPartcipants;\n\n\t\t\tstd::wstring summNames;\n\t\t\tbool isRanked = false;\n\n\t\t\tif (reader->parse(champSelect.c_str(), champSelect.c_str() + static_cast<int>(champSelect.length()), &rootCSelect, &err))\n\t\t\t{\n\t\t\t\tauto teamArr = rootCSelect[\"myTeam\"];\n\t\t\t\tif (teamArr.isArray())\n\t\t\t\t{\n\t\t\t\t\tfor (auto& i : teamArr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (i[\"nameVisibilityType\"].asString() == \"HIDDEN\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tisRanked = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstd::string summId = i[\"summonerId\"].asString();\n\t\t\t\t\t\tif (summId != \"0\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::string summoner = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners/\" + summId);\n\t\t\t\t\t\t\tif (reader->parse(summoner.c_str(), summoner.c_str() + static_cast<int>(summoner.length()), &rootSummoner, &err))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsummNames += Utils::StringToWstring(rootSummoner[\"gameName\"].asString()) + L\"%23\" + Utils::StringToWstring(rootSummoner[\"tagLine\"].asString()) + L\",\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t//\tRanked Lobby Reveal\n\t\t\t\t\tif (isRanked)\n\t\t\t\t\t{\n\t\t\t\t\t\tsummNames = L\"\";\n\n\t\t\t\t\t\tLCU::SetCurrentClientRiotInfo();\n\t\t\t\t\t\tstd::string participants = cpr::Get(\n\t\t\t\t\t\t\tcpr::Url{ std::format(\"https://127.0.0.1:{}/chat/v5/participants\", LCU::riot.port) },\n\t\t\t\t\t\t\tcpr::Header{ Utils::StringToHeader(LCU::riot.header) }, cpr::VerifySsl{ false }).text;\n\t\t\t\t\t\tif (reader->parse(participants.c_str(), participants.c_str() + static_cast<int>(participants.length()), &rootPartcipants,\n\t\t\t\t\t\t\t&err))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tauto participantsArr = rootPartcipants[\"participants\"];\n\t\t\t\t\t\t\tif (participantsArr.isArray())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto& i : participantsArr)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!i[\"cid\"].asString().contains(\"champ-select\"))\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tsummNames += Utils::StringToWstring(i[\"game_name\"].asString()) + L\"%23\" + Utils::StringToWstring(i[\"game_tag\"].asString()) + L\",\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::wstring region;\n\t\t\t\t\tif (website == \"U.GG\") // platformId (euw1, eun1, na1)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string getAuthorization = LCU::Request(\"GET\", \"/lol-rso-auth/v1/authorization\");\n\t\t\t\t\t\tif (reader->parse(getAuthorization.c_str(), getAuthorization.c_str() + static_cast<int>(getAuthorization.length()),\n\t\t\t\t\t\t\t&rootRegion, &err))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tregion = Utils::StringToWstring(rootRegion[\"currentPlatformId\"].asString());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse // region code (euw, eune na)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string getRegion = LCU::Request(\"GET\", \"/riotclient/region-locale\");\n\t\t\t\t\t\tif (reader->parse(getRegion.c_str(), getRegion.c_str() + static_cast<int>(getRegion.length()), &rootRegion, &err))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tregion = Utils::StringToWstring(rootRegion[\"webRegion\"].asString());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!region.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (summNames.empty())\n\t\t\t\t\t\t\treturn \"Failed to get summoner names\";\n\n\t\t\t\t\t\tif (summNames.at(summNames.size() - 1) == L',')\n\t\t\t\t\t\t\tsummNames.pop_back();\n\n\t\t\t\t\t\tstd::wstring url;\n\t\t\t\t\t\tif (website == \"OP.GG\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl = L\"https://\" + region + L\".op.gg/multi/query=\" + summNames;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (website == \"U.GG\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl = L\"https://u.gg/multisearch?summoners=\" + summNames + L\"&region=\" + Utils::ToLower(region);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (website == \"PORO.GG\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl = L\"https://poro.gg/multi?region=\" + Utils::ToUpper(region) + L\"&q=\" + summNames;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (website == \"Porofessor.gg\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl = L\"https://porofessor.gg/pregame/\" + region + L\"/\" + summNames + L\"/soloqueue/season\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tUtils::OpenUrl(url.c_str(), nullptr, SW_SHOW);\n\t\t\t\t\t\treturn Utils::WstringToString(url);\n\t\t\t\t\t}\n\t\t\t\t\treturn \"Failed to get region\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn \"Champion select not found\";\n\t}\n\n\tstatic std::string ChangeRunesOpgg()\n\t{\n\t\t//std::string champSelect = LCU::Request(\"GET\", \"/lol-champ-select/v1/session\");\n\t\t//if (champSelect.empty() || champSelect.find(\"RPC_ERROR\") != std::string::npos)\n\t\t//{\n\t\t//\treturn \"Champion select not found\";\n\t\t//}\n\n\t\tJson::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value rootCurrentPage;\n\t\t//Json::Value rootCSelect;\n\n\t\t//if (!reader->parse(champSelect.c_str(), champSelect.c_str() + static_cast<int>(champSelect.length()), &rootCSelect, &err))\n\t\t//{\n\t\t//\treturn \"Failed to get champion select\";\n\t\t//}\n\n\t\tstd::string currentChampion = LCU::Request(\"GET\", \"/lol-champ-select/v1/current-champion\");\n\t\tif (currentChampion == \"0\" || currentChampion.empty() || currentChampion.find(\"RPC_ERROR\") != std::string::npos)\n\t\t{\n\t\t\treturn \"Champion not picked\";\n\t\t}\n\n\t\tstd::string currentChampionName;\n\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t{\n\t\t\tif (std::stoi(currentChampion) == key)\n\t\t\t{\n\t\t\t\tcurrentChampionName = name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tstd::string getCurrentPage = LCU::Request(\"GET\", \"/lol-perks/v1/currentpage\");\n\t\tif (!reader->parse(getCurrentPage.c_str(), getCurrentPage.c_str() + static_cast<int>(getCurrentPage.length()), &rootCurrentPage, &err))\n\t\t{\n\t\t\treturn \"Failed to get current rune page\";\n\t\t}\n\t\tstd::string currentPageId = rootCurrentPage[\"id\"].asString();\n\n\t\tstd::stringstream ssOpgg(cpr::Get(cpr::Url{ \"https://www.op.gg/champions/\" + Utils::ToLower(currentChampionName) }).text);\n\t\tstd::vector<std::string> runes;\n\t\tstd::string primaryPerk, secondaryPerk;\n\n\t\tstd::string buf;\n\t\twhile (ssOpgg >> buf)\n\t\t{\n\t\t\tif (runes.size() == 9)\n\t\t\t\tbreak;\n\n\t\t\tif (buf.find(\"src=\\\"https://opgg-static.akamaized.net/images/lol/perk\") != std::string::npos\n\t\t\t\t|| buf.find(\"src=\\\"https://opgg-static.akamaized.net/meta/images/lol/perk\") != std::string::npos)\n\t\t\t{\n\t\t\t\tif (buf.find(\"grayscale\") != std::string::npos)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (buf.find(\"/perkStyle/\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tbuf = buf.substr(buf.find(\"/perkStyle/\") + strlen(\"/perkStyle/\"), 4);\n\t\t\t\t\tif (primaryPerk.empty())\n\t\t\t\t\t\tprimaryPerk = buf;\n\t\t\t\t\telse if (secondaryPerk.empty())\n\t\t\t\t\t\tsecondaryPerk = buf;\n\t\t\t\t}\n\t\t\t\telse if (buf.find(\"/perk/\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tbuf = buf.substr(buf.find(\"/perk/\") + strlen(\"/perk/\"), 4);\n\t\t\t\t\trunes.emplace_back(buf);\n\t\t\t\t}\n\t\t\t\telse if (buf.find(\"/perkShard/\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tbuf = buf.substr(buf.find(\"/perkShard/\") + strlen(\"/perkShard/\"), 4);\n\t\t\t\t\trunes.emplace_back(buf);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (runes.size() != 9 || primaryPerk.empty() || secondaryPerk.empty())\n\t\t{\n\t\t\treturn \"Failed to fetch op.gg runes\";\n\t\t}\n\n\t\tLCU::Request(\"DELETE\", \"/lol-perks/v1/pages/\" + currentPageId);\n\n\t\tJson::Value rootPage;\n\t\trootPage[\"name\"] = currentChampionName + \" OP.GG\";\n\t\trootPage[\"primaryStyleId\"] = primaryPerk;\n\t\trootPage[\"subStyleId\"] = secondaryPerk;\n\t\trootPage[\"selectedPerkIds\"] = Json::Value(Json::arrayValue);\n\t\tfor (const std::string& rune : runes)\n\t\t\trootPage[\"selectedPerkIds\"].append(rune);\n\t\trootPage[\"current\"] = true;\n\n\t\treturn LCU::Request(\"POST\", \"lol-perks/v1/pages\", rootPage.toStyledString());\n\t}\n\n\tstatic std::string ChampIdToName(const int& id)\n\t{\n\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t{\n\t\t\tif (id == key)\n\t\t\t{\n\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t// TODO: rewrite and move these to config file\n\tstatic std::string GetOldJWT(std::string accId, int& oldtimestamp)\n\t{\n\t\tchar* pRoaming;\n\t\tsize_t roamingLen;\n\t\t[[maybe_unused]] errno_t err = _dupenv_s(&pRoaming, &roamingLen, \"APPDATA\");\n\t\tstd::string roaming = pRoaming;\n\t\tstd::string filePath = roaming + \"\\\\tempar.json\";\n\n\t\tstd::fstream file(filePath, std::ios_base::in);\n\t\tif (file.good())\n\t\t{\n\t\t\tstd::string config;\n\t\t\tstd::string temp;\n\t\t\twhile (std::getline(file, temp))\n\t\t\t{\n\t\t\t\tconfig += temp + \"\\n\";\n\t\t\t}\n\n\t\t\tJson::Value root;\n\t\t\tJson::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING local_err;\n\n\t\t\tif (reader->parse(config.c_str(), config.c_str() + static_cast<int>(config.length()), &root, &local_err))\n\t\t\t{\n\t\t\t\tif (auto t = root[accId]; !t.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string oldJWT;\n\t\t\t\t\tif (auto t2 = root[accId][\"time\"]; !t2.empty())\n\t\t\t\t\t\toldtimestamp = t2.asUInt();\n\t\t\t\t\tif (auto t2 = root[accId][\"jwt\"]; !t2.empty())\n\t\t\t\t\t\toldJWT = t2.asString();\n\t\t\t\t\tfile.close();\n\t\t\t\t\treturn oldJWT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfile.close();\n\t\treturn {};\n\t}\n\n\t// true if need new jwt\n\tstatic bool CheckJWT(std::string accId)\n\t{\n\t\tchar* pRoaming;\n\t\tsize_t roamingLen;\n\t\t[[maybe_unused]] errno_t err = _dupenv_s(&pRoaming, &roamingLen, \"APPDATA\");\n\t\tstd::string roaming = pRoaming;\n\t\tstd::string filePath = roaming + \"\\\\tempar.json\";\n\t\tunsigned timestamp = 0;\n\n\t\tstd::fstream file(filePath, std::ios_base::in);\n\t\tif (file.good())\n\t\t{\n\t\t\tstd::string config;\n\t\t\tstd::string temp;\n\t\t\twhile (std::getline(file, temp))\n\t\t\t{\n\t\t\t\tconfig += temp + \"\\n\";\n\t\t\t}\n\n\t\t\tJson::Value root;\n\t\t\tJson::CharReaderBuilder builder;\n\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\tJSONCPP_STRING local_err;\n\n\t\t\tif (reader->parse(config.c_str(), config.c_str() + static_cast<int>(config.length()), &root, &local_err))\n\t\t\t{\n\t\t\t\tif (auto t = root[accId]; !t.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string oldJWT; // CppEntityAssignedButNoRead\n\t\t\t\t\tif (auto t2 = root[accId][\"time\"]; !t2.empty())\n\t\t\t\t\t\ttimestamp = t2.asUInt();\n\t\t\t\t\tif (auto t2 = root[accId][\"jwt\"]; !t2.empty())\n\t\t\t\t\t\toldJWT = t2.asString();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfile.close();\n\n\t\t// if old timestamp is still valid\n\t\tif (timestamp + 60 * 60 * 24 > time(nullptr))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n#pragma warning ( push )\n#pragma warning (disable : 4996)\n\tstatic void SaveJWT(std::string accId, std::string jwt, unsigned timestamp)\n\t{\n\t\tchar* pRoaming;\n\t\tsize_t roamingLen;\n\t\t[[maybe_unused]] errno_t err = _dupenv_s(&pRoaming, &roamingLen, \"APPDATA\");\n\t\tstd::string roaming = pRoaming;\n\t\tstd::string filePath = roaming + \"\\\\tempar.json\";\n\t\t// if file doesn't exist, create new one with {} so it can be parsed\n\t\tif (!std::filesystem::exists(filePath))\n\t\t{\n\t\t\tstd::ofstream file(filePath);\n\t\t\tfile << \"{}\";\n\t\t\tfile.close();\n\t\t}\n\n\t\t/** \\\n\t\t* \\deprecated Use CharReader and CharReaderBuilder.\n\t\t*/\n\t\tJson::Reader reader;\n\t\tJson::Value root;\n\n\t\tstd::ifstream iFile(filePath);\n\t\tif (iFile.good())\n\t\t{\n\t\t\tif (reader.parse(iFile, root, false))\n\t\t\t{\n\t\t\t\troot[accId][\"jwt\"] = jwt;\n\t\t\t\troot[accId][\"time\"] = timestamp;\n\n\t\t\t\tif (!root.toStyledString().empty())\n\t\t\t\t{\n\t\t\t\t\tstd::ofstream oFile(filePath);\n\t\t\t\t\toFile << root.toStyledString() << std::endl;\n\t\t\t\t\toFile.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tiFile.close();\n\t}\n#pragma warning( pop )\n};\n"
  },
  {
    "path": "KBotExt/Includes.h",
    "content": "#pragma once\n\n#include <thread>\n#include <chrono>\n#include <iostream>\n#include <filesystem>\n#include <regex>\n#include <utility>\n\n#include <json/json.h>\n\n#include <imgui.h>\n#include <imgui_impl_win32.h>\n#include <imgui_impl_dx11.h>\n#include \"imgui_freetype.h\"\n"
  },
  {
    "path": "KBotExt/InfoTab.h",
    "content": "#pragma once\n\n#include \"Includes.h\"\n#include \"Utils.h\"\n#include \"LCU.h\"\n#include \"Config.h\"\n\nclass InfoTab\n{\npublic:\n\tstatic void Render()\n\t{\n\t\tif (ImGui::BeginTabItem(\"Info\"))\n\t\t{\n\t\t\tstatic bool once = true;\n\t\t\tstatic std::string result;\n\t\t\tstatic bool bPressed = false;\n\n\t\t\tstatic std::string accID;\n\t\t\tstatic std::string summID;\n\t\t\tstatic std::string summName;\n\t\t\tstatic std::string gameName;\n\t\t\tstatic std::string tagLine;\n\n\t\t\tstatic char playerName[50];\n\t\t\tif (once)\n\t\t\t{\n\t\t\t\tonce = false;\n\t\t\t\tstd::ranges::copy(S.infoTab.playerName, playerName);\n\t\t\t}\n\n\t\t\tImGui::Text(\"Input player name:\");\n\t\t\tImGui::InputText(\"##inputPlayerName\", playerName, IM_ARRAYSIZE(playerName));\n\t\t\tS.infoTab.playerName = playerName;\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Submit##playerName\") || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter), false))\n\t\t\t{\n\t\t\t\tstd::string tempName = std::string(playerName);\n\t\t\t\ttempName.erase(std::remove_if(tempName.begin(), tempName.end(),\n\t\t\t\t\t[](unsigned char x) { return std::isspace(x); }), tempName.end());\n\n\t\t\t\tsize_t found;\n\t\t\t\twhile ((found = tempName.find(\"#\")) != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\ttempName.replace(found, 1, \"%23\");\n\t\t\t\t}\n\n\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners?name=\" + tempName);\n\n\t\t\t\t// 2nd method\n\t\t\t\t/*auto riotId = Utils::StringSplit(tempName, \"#\");\n\t\t\t\tif (riotId.size() > 1)\n\t\t\t\t{\n\t\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/alias/lookup?gameName=\" + riotId[0] + \"&tagLine=\" + riotId[1]);\n\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string puuid = root[\"puuid\"].asString();\n\t\t\t\t\t\tif (puuid != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners-by-puuid-cached/\" + puuid);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}*/\n\n\t\t\t\tbPressed = true;\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"puuid##playerName\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners-by-puuid-cached/\" + std::string(playerName));\n\t\t\t\tbPressed = true;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"summId##playerName\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners/\" + std::string(playerName));\n\t\t\t\tbPressed = true;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Me##playerName\"))\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\n\t\t\t\tstd::string mySummId;\n\n\t\t\t\tstd::string getSession = LCU::Request(\"GET\", \"https://127.0.0.1/lol-login/v1/session\");\n\t\t\t\tif (reader->parse(getSession.c_str(), getSession.c_str() + static_cast<int>(getSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tmySummId = root[\"summonerId\"].asString();\n\t\t\t\t}\n\n\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-summoner/v1/summoners/\" + mySummId);\n\t\t\t\tbPressed = true;\n\t\t\t}\n\n\t\t\tstatic Json::StreamWriterBuilder wBuilder;\n\t\t\tstatic std::string sResultJson;\n\t\t\tstatic char* cResultJson;\n\n\t\t\tif (bPressed)\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (!reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t\t\t\tsResultJson = result;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taccID = std::to_string(root[\"accountId\"].asUInt64());\n\t\t\t\t\tsummID = std::to_string(root[\"summonerId\"].asUInt64());\n\t\t\t\t\tsummName = root[\"internalName\"].asString();\n\t\t\t\t\tgameName = root[\"gameName\"].asString();\n\t\t\t\t\ttagLine = root[\"tagLine\"].asString();\n\n\t\t\t\t\tsResultJson = Json::writeString(wBuilder, root); // \"CppRedundantQualifier\"\n\t\t\t\t}\n\n\t\t\t\t//accID = std::to_string(root[\"accountId\"].asUInt64()).c_str();\n\t\t\t\t//ImGui::Text(\"accountId: %s\", accID.c_str());\n\t\t\t\t//ImGui::TextWrapped(\"displayName: %s\", root[\"displayName\"].asString().c_str());\n\t\t\t\t//summName = root[\"internalName\"].asString().c_str();\n\t\t\t\t//ImGui::TextWrapped(\"internalName: %s\", summName.c_str());\n\t\t\t\t//ImGui::Text(\"nameChangeFlag: %d\", root[\"nameChangeFlag\"].asBool());\n\t\t\t\t//ImGui::Text(\"percentCompleteForNextLevel: %d\", root[\"percentCompleteForNextLevel\"].asInt());\n\t\t\t\t//ImGui::Text(\"profileIconId: %d\", root[\"profileIconId\"].asInt());\n\t\t\t\t//ImGui::Text(\"puuid: %s\", root[\"puuid\"].asString().c_str());\n\t\t\t\t//summID = std::to_string(root[\"summonerId\"].asUInt64()).c_str();;\n\t\t\t\t//ImGui::Text(\"summonerId: %d\", summID);\n\t\t\t\t//ImGui::Text(\"summonerLevel: %d\", root[\"summonerLevel\"].asInt());\n\t\t\t\t//ImGui::Text(\"unnamed: %d\", root[\"unnamed\"].asBool());\n\t\t\t\t//ImGui::Text(\"xpSinceLastLevel: %d\", root[\"xpSinceLastLevel\"].asInt());\n\t\t\t\t//ImGui::Text(\"xpUntilNextLevel: %d\", root[\"xpUntilNextLevel\"].asInt());\n\n\t\t\t\t//auto& rerollPointsObj = root[\"rerollPoints\"];\n\t\t\t\t//ImGui::Text(\"currentPoints: %d\", rerollPointsObj[\"currentPoints\"].asInt());\n\t\t\t\t//ImGui::Text(\"maxRolls: %d\", rerollPointsObj[\"maxRolls\"].asInt());\n\t\t\t\t//ImGui::Text(\"numberOfRolls: %d\", rerollPointsObj[\"numberOfRolls\"].asInt());\n\t\t\t\t//ImGui::Text(\"pointsCostToRoll: %d\", rerollPointsObj[\"pointsCostToRoll\"].asInt());\n\t\t\t\t//ImGui::Text(\"pointsToReroll: %d\", rerollPointsObj[\"pointsToReroll\"].asInt());\n\t\t\t}\n\n\t\t\tif (!sResultJson.empty())\n\t\t\t{\n\t\t\t\tcResultJson = sResultJson.data();\n\t\t\t\tImGui::InputTextMultiline(\"##infoResult\", cResultJson, sResultJson.size() + 1, ImVec2(600, 350));\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Invite to lobby##infoTab\"))\n\t\t\t{\n\t\t\t\tstd::string invite = R\"([{\"toSummonerId\":)\" + accID + R\"(}])\";\n\t\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby/invitations\", invite);\n\t\t\t\tinvite = R\"([{\"toSummonerId\":)\" + summID + R\"(}])\";\n\t\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/lol-lobby/v2/lobby/invitations\", invite);\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Invite to friends##infoTab\"))\n\t\t\t{\n\t\t\t\tstd::string invite = R\"({\"gameName\":\")\" + gameName + R\"(\",\"tagLine\":\")\" + tagLine + R\"(\"})\";\n\t\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/lol-chat/v2/friend-requests\", invite);\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Add to block list##infoTab\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({ \"summonerId\":)\" + summID + \"}\";\n\t\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/lol-chat/v1/blocked-players\", body);\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Copy to clipboard##infoTab\"))\n\t\t\t{\n\t\t\t\tUtils::CopyToClipboard(sResultJson);\n\t\t\t}\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t}\n};\n"
  },
  {
    "path": "KBotExt/KBotExt.cpp",
    "content": "﻿#pragma comment (lib, \"cpr.lib\")\n//#pragma comment (lib, \"libcurl.lib\")\n#pragma comment (lib, \"Ws2_32.lib\")\n#pragma comment (lib, \"Wldap32.lib\")\n#pragma comment (lib, \"Crypt32.lib\")\n\n#include <chrono>\n#include <string>\n#include <thread>\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"DirectX.h\"\n#include \"LCU.h\"\n#include \"Utils.h\"\n#include \"Config.h\"\n\nSettings S;\n\nDirect3D11Render Direct3D11;\n\nLRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);\n\nint WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPWSTR /*lpCmdLine*/, int /*nCmdShow*/)\n{\n\tLPWSTR* szArgList;\n\tint argCount;\n\tszArgList = CommandLineToArgvW(GetCommandLineW(), &argCount);\n\tstd::wstring programPath = szArgList[0];\n\tstd::wstring programName = programPath.substr(programPath.find_last_of(L\"/\\\\\") + 1);\n\tif (argCount > 1)\n\t{\n\t\tstd::string applicationName = Utils::WstringToString(szArgList[1]); // league\n\t\tstd::string cmdLine;\n\t\tfor (int i = 2; i < argCount; i++)\n\t\t{\n\t\t\tcmdLine += \"\\\"\" + Utils::WstringToString(szArgList[i]) + \"\\\" \";\n\t\t}\n\n\t\tcmdLine.replace(cmdLine.find(\"\\\"--no-proxy-server\\\"\"), strlen(\"\\\"--no-proxy-server\\\"\"), \"\");\n\n\t\tAllocConsole();\n\t\tFILE* f;\n\t\tfreopen_s(&f, \"CONOUT$\", \"w\", stdout);\n\n\t\tSTARTUPINFOA startupInfo = {};\n\t\tstartupInfo.cb = sizeof(startupInfo);\n\t\tPROCESS_INFORMATION processInformation = {};\n\n\t\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\t\tstatic auto pCreateProcessA = (decltype(&CreateProcessA))GetProcAddress(kernel32, \"CreateProcessA\");\n\t\tif (!pCreateProcessA(applicationName.c_str(), const_cast<char*>(cmdLine.c_str()), nullptr, nullptr, false, 2U, nullptr, nullptr, &startupInfo,\n\t\t\t&processInformation))\n\t\t\treturn 0;\n\n\t\tstd::cout << \"App: \" << applicationName << std::endl;\n\t\tstd::cout << \"PID: \" << processInformation.dwProcessId << std::endl;\n\t\tstd::cout << \"Args: \" << cmdLine << std::endl;\n\n\t\tstatic auto pDebugActiveProcessStop = (decltype(&DebugActiveProcessStop))GetProcAddress(kernel32, \"DebugActiveProcessStop\");\n\t\tif (!pDebugActiveProcessStop(processInformation.dwProcessId))\n\t\t{\n\t\t\tCloseHandle(processInformation.hProcess);\n\t\t\tCloseHandle(processInformation.hThread);\n\t\t\tfclose(f);\n\t\t\tFreeConsole();\n\t\t\treturn 0;\n\t\t}\n\n\t\tstatic auto pWaitForSingleObject = (decltype(&WaitForSingleObject))GetProcAddress(kernel32, \"WaitForSingleObject\");\n\t\tpWaitForSingleObject(processInformation.hProcess, INFINITE);\n\n\t\tstd::cout << \"Exited\" << std::endl;\n\n\t\tCloseHandle(processInformation.hProcess);\n\t\tCloseHandle(processInformation.hThread);\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\tfclose(f);\n\t\tFreeConsole();\n\t}\n\telse\n\t{\n#ifndef NDEBUG\n\t\tAllocConsole();\n\t\tFILE* f;\n\t\tfreopen_s(&f, \"CONOUT$\", \"w\", stdout);\n#endif\n\n\t\t//Randomize using current time\n\t\t//TODO: swap with recent c++ random\n\t\t//srand(static_cast<unsigned>(time(nullptr)));\n\n\t\tConfig::Load();\n\t\tstd::wstring sClassName = Utils::RandomWString(Utils::RandomInt(5, 10), { 0x2e80, 0xfffff });\n\t\tLPCWSTR lpszOverlayClassName = sClassName.c_str();\n\t\t//Register window class information\n\t\tWNDCLASSEXW wc = {\n\t\t\tsizeof(WNDCLASSEXW), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, sClassName.c_str(),\n\t\t\tnullptr\n\t\t};\n\n\t\tif (S.autoRename)\n\t\t\tS.fileName = Utils::RenameExe();\n\n\t\tRegisterClassExW(&wc);\n\n\t\t// Create application window\n\t\tS.hwnd = ::CreateWindowW(sClassName.c_str(), lpszOverlayClassName, WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX, 100, 100,\n\t\t\tS.Window.width, S.Window.height, NULL, NULL, wc.hInstance, NULL);\n\n\t\tif (S.hwnd == nullptr)\n\t\t{\n\t\t\tUnregisterClassW(wc.lpszClassName, wc.hInstance);\n\t\t\tMessageBoxA(nullptr, \"Couldn't create window\", nullptr, 0);\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (S.streamProof)\n\t\t\tSetWindowDisplayAffinity(S.hwnd, WDA_EXCLUDEFROMCAPTURE);\n\t\telse\n\t\t\tSetWindowDisplayAffinity(S.hwnd, WDA_NONE);\n\n\t\t//Initialize Direct3D\n\t\tif (!Direct3D11.DirectXInit(S.hwnd))\n\t\t{\n\t\t\tDirect3D11Render::Shutdown();\n\t\t\tUnregisterClassW(wc.lpszClassName, wc.hInstance);\n\t\t\tMessageBoxA(nullptr, \"Couldn't initialize DirectX\", nullptr, 0);\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Show the window\n\t\tShowWindow(S.hwnd, SW_SHOWDEFAULT);\n\t\tUpdateWindow(S.hwnd);\n\n\t\tLCU::GetLeagueProcesses();\n\n\t\tif (LCU::SetLeagueClientInfo())\n\t\t{\n\t\t\t//league client is running\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//riot client with login screen is up\n\t\t\tLCU::SetRiotClientInfo();\n\t\t}\n\n\t\tbool closedNow = false;\n\t\tbool done = false;\n\t\t// Main loop\n\t\tMSG msg;\n\t\tZeroMemory(&msg, sizeof(msg));\n\t\twhile (msg.message != WM_QUIT)\n\t\t{\n\t\t\t//auto timeBefore = std::chrono::high_resolution_clock::now();\n\n\t\t\tif (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))\n\t\t\t{\n\t\t\t\tTranslateMessage(&msg);\n\t\t\t\t::DispatchMessage(&msg);\n\t\t\t\tif (msg.message == WM_QUIT)\n\t\t\t\t\tdone = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (done)\n\t\t\t\tbreak;\n\n\t\t\t//Start rendering\n\t\t\tDirect3D11Render::StartFrame();\n\n\t\t\t//Render UI\n\t\t\tDirect3D11.Render();\n\n\t\t\t//End rendering\n\t\t\tDirect3D11Render::EndFrame();\n\n\t\t\t// idle if client closed and reconnect to it\n\t\t\tif (!FindWindowA(\"RCLIENT\", \"League of Legends\"))\n\t\t\t{\n\t\t\t\tDirect3D11.closedClient = true;\n\t\t\t\tclosedNow = true;\n\t\t\t\tif (!LCU::leagueProcesses.empty())\n\t\t\t\t\tLCU::leagueProcesses.clear();\n\t\t\t\tif (FindWindowA(NULL, \"Riot Client\"))\n\t\t\t\t{\n\t\t\t\t\tif (LCU::riot.port == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tLCU::SetRiotClientInfo();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tLCU::riot.port = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (closedNow)\n\t\t\t{\n\t\t\t\tLCU::GetLeagueProcesses();\n\t\t\t\tLCU::SetLeagueClientInfo();\n\n\t\t\t\tDirect3D11.closedClient = false;\n\t\t\t\tclosedNow = false;\n\t\t\t}\n\n\t\t\t//std::chrono::duration<float, std::milli> timeDuration = std::chrono::high_resolution_clock::now() - timeBefore;\n\t\t\t//processTimeMs = timeDuration.count();\n\n\t\t\t//std::cout << processTimeMs << std::endl;\n\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t}\n\n\t\tConfig::Save();\n\n\t\t// Cleanup\n\t\tImGui_ImplDX11_Shutdown();\n\t\tImGui_ImplWin32_Shutdown();\n\t\tImGui::DestroyContext();\n\n#ifndef NDEBUG\n\t\tfclose(f);\n\t\tFreeConsole();\n#endif\n\n\t\t//Exit\n\t\tDirect3D11Render::Shutdown();\n\t\tDestroyWindow(S.hwnd);\n\t\tUnregisterClassW(wc.lpszClassName, wc.hInstance);\n\t}\n\treturn 0;\n}\n\n// Forward declare message handler from imgui_impl_win32.cpp\nextern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);\n\n// Win32 message handler\nLRESULT WINAPI WndProc(const HWND hWnd, const UINT msg, const WPARAM wParam, const LPARAM lParam)\n{\n\tif (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))\n\t\treturn true;\n\n\tswitch (msg)\n\t{\n\tcase WM_SIZE:\n\t\tif (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED)\n\t\t{\n\t\t\tDirect3D11Render::CleanupRenderTarget();\n\t\t\tg_pSwapChain->ResizeBuffers(0, LOWORD(lParam), HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0);\n\t\t\tDirect3D11Render::CreateRenderTarget();\n\n\t\t\tRECT rect;\n\t\t\tif (GetWindowRect(hWnd, &rect))\n\t\t\t{\n\t\t\t\tS.Window.height = rect.bottom - rect.top;\n\t\t\t\tS.Window.width = rect.right - rect.left;\n\t\t\t\tConfig::Save();\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\tcase WM_SYSCOMMAND:\n\t\tif ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu\n\t\t\treturn 0;\n\t\tbreak;\n\tcase WM_DESTROY:\n\t\tPostQuitMessage(0);\n\t\treturn 0;\n\tdefault:;\n\t}\n\treturn DefWindowProcW(hWnd, msg, wParam, lParam);\n}"
  },
  {
    "path": "KBotExt/KBotExt.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{1f8647c7-3a8d-4aa4-9f22-778ffad47c75}</ProjectGuid>\n    <RootNamespace>KBotExt</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <VcpkgTriplet Condition=\"'$(Platform)'=='Win32'\">x86-windows-static</VcpkgTriplet>\n    <VcpkgTriplet Condition=\"'$(Platform)'=='x64'\">x64-windows-static</VcpkgTriplet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <TargetName>$(ProjectName)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <TargetName>$(ProjectName)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Vcpkg\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <VcpkgUseStatic>true</VcpkgUseStatic>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Vcpkg\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <VcpkgUseStatic>true</VcpkgUseStatic>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_WINDOWS;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpplatest</LanguageStandard>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\KBotExt;$(SolutionDir)\\KBotExt\\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpplatest</LanguageStandard>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\KBotExt\\imgui;$(SolutionDir)\\KBotExt</AdditionalIncludeDirectories>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_WINDOWS;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\KBotExt;$(SolutionDir)\\KBotExt\\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpplatest</LanguageStandard>\n      <EnableModules>true</EnableModules>\n      <FloatingPointModel>\n      </FloatingPointModel>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\KBotExt;$(SolutionDir)\\KBotExt\\imgui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpplatest</LanguageStandard>\n      <DebugInformationFormat>None</DebugInformationFormat>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <EnableModules>false</EnableModules>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <FloatingPointModel />\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Auth.cpp\" />\n    <ClCompile Include=\"DirectX.cpp\" />\n    <ClCompile Include=\"imgui\\imgui.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_draw.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_freetype.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_impl_dx11.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_impl_win32.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_tables.cpp\" />\n    <ClCompile Include=\"imgui\\imgui_widgets.cpp\" />\n    <ClCompile Include=\"KBotExt.cpp\" />\n    <ClCompile Include=\"LCU.cpp\" />\n    <ClCompile Include=\"Utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Auth.h\" />\n    <ClInclude Include=\"base64.h\" />\n    <ClInclude Include=\"ChampsTab.h\" />\n    <ClInclude Include=\"CustomTab.h\" />\n    <ClInclude Include=\"Definitions.h\" />\n    <ClInclude Include=\"DirectX.h\" />\n    <ClInclude Include=\"GameTab.h\" />\n    <ClInclude Include=\"imgui\\imconfig.h\" />\n    <ClInclude Include=\"imgui\\imgui.h\" />\n    <ClInclude Include=\"imgui\\imgui_freetype.h\" />\n    <ClInclude Include=\"imgui\\imgui_impl_dx11.h\" />\n    <ClInclude Include=\"imgui\\imgui_impl_win32.h\" />\n    <ClInclude Include=\"imgui\\imgui_internal.h\" />\n    <ClInclude Include=\"imgui\\imstb_rectpack.h\" />\n    <ClInclude Include=\"imgui\\imstb_textedit.h\" />\n    <ClInclude Include=\"Includes.h\" />\n    <ClInclude Include=\"InfoTab.h\" />\n    <ClInclude Include=\"LCU.h\" />\n    <ClInclude Include=\"LoginTab.h\" />\n    <ClInclude Include=\"Misc.h\" />\n    <ClInclude Include=\"MiscTab.h\" />\n    <ClInclude Include=\"ProfileTab.h\" />\n    <ClInclude Include=\"Config.h\" />\n    <ClInclude Include=\"SettingsTab.h\" />\n    <ClInclude Include=\"SkinsTab.h\" />\n    <ClInclude Include=\"Utils.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "KBotExt/KBotExt.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Tabs\">\n      <UniqueIdentifier>{7d0b8c55-703b-4c67-b79b-56f9c8dbbf02}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"League\">\n      <UniqueIdentifier>{888bd346-de16-4def-9ccf-4c21e22c708b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"imgui\">\n      <UniqueIdentifier>{ed321358-528e-43a8-b1aa-992806430647}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"DirectX.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"KBotExt.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Utils.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Auth.cpp\">\n      <Filter>League</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_draw.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_impl_dx11.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_impl_win32.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_widgets.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"LCU.cpp\">\n      <Filter>League</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_freetype.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n    <ClCompile Include=\"imgui\\imgui_tables.cpp\">\n      <Filter>imgui</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"DirectX.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Utils.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Definitions.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Includes.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoginTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"InfoTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"base64.h\">\n      <Filter>League</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Auth.h\">\n      <Filter>League</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imconfig.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imgui.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imgui_impl_dx11.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imgui_impl_win32.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imgui_internal.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imstb_rectpack.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imstb_textedit.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Misc.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProfileTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CustomTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SkinsTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChampsTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SettingsTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Config.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MiscTab.h\">\n      <Filter>Tabs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LCU.h\">\n      <Filter>League</Filter>\n    </ClInclude>\n    <ClInclude Include=\"imgui\\imgui_freetype.h\">\n      <Filter>imgui</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "KBotExt/KBotExt.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup />\n</Project>"
  },
  {
    "path": "KBotExt/LCU.cpp",
    "content": "#include <json/json.h>\n#include <thread>\n#include \"Utils.h\"\n\n#include \"LCU.h\"\n\n[[maybe_unused]] static void FixCachingProblem();\n\nstd::string LCU::Request(const std::string& method, const std::string& endpoint, const std::string& body)\n{\n\tif (league.port == 0)\n\t\treturn \"Not connected to League\";\n\tstd::string sURL = endpoint;\n\tif (sURL.find(\"https://127.0.0.1\") == std::string::npos)\n\t{\n\t\tif (sURL.find(\"https://\") == std::string::npos && sURL.find(\"http://\") == std::string::npos)\n\t\t{\n\t\t\twhile (sURL[0] == ' ')\n\t\t\t\tsURL.erase(sURL.begin());\n\t\t\tif (sURL[0] != '/')\n\t\t\t\tsURL.insert(0, \"/\");\n\t\t\tsURL.insert(0, \"https://127.0.0.1:\" + std::to_string(league.port));\n\t\t}\n\t}\n\telse if (sURL.find(\"https://127.0.0.1:\") == std::string::npos)\n\t{\n\t\tsURL.insert(strlen(\"https://127.0.0.1\"), \":\" + std::to_string(league.port));\n\t}\n\n\tcpr::Response r = {};\n\n\tsession.SetUrl(sURL);\n\tsession.SetBody(body);\n\n\tif (const std::string upperMethod = Utils::ToUpper(method); upperMethod == \"GET\")\n\t{\n\t\tr = session.Get();\n\t}\n\telse if (upperMethod == \"POST\")\n\t{\n\t\tr = session.Post();\n\t}\n\telse if (upperMethod == \"OPTIONS\")\n\t{\n\t\tr = session.Options();\n\t}\n\telse if (upperMethod == \"DELETE\")\n\t{\n\t\tr = session.Delete();\n\t}\n\telse if (upperMethod == \"PUT\")\n\t{\n\t\tr = session.Put();\n\t}\n\telse if (upperMethod == \"HEAD\")\n\t{\n\t\tr = session.Head();\n\t}\n\telse if (upperMethod == \"PATCH\")\n\t{\n\t\tr = session.Patch();\n\t}\n\n\treturn r.text;\n}\n\nbool LCU::SetRiotClientInfo(const ClientInfo& info)\n{\n\triot = info;\n\n\tif (riot.port == 0 || riot.token == \"\")\n\t\treturn false;\n\n\triot.header = Auth::MakeRiotHeader(info);\n\n\treturn true;\n}\n\nbool LCU::SetRiotClientInfo()\n{\n\tconst auto riotClients = Auth::GetAllProcessIds(L\"Riot Client.exe\");\n\tfor (const DWORD& clientPid : riotClients)\n\t{\n\t\tconst auto info = Auth::GetClientInfo(clientPid);\n\t\tif (info.port == 0)\n\t\t\tcontinue;\n\t\treturn SetRiotClientInfo(info);\n\t}\n\treturn false;\n}\n\nbool LCU::SetLeagueClientInfo(const ClientInfo& info)\n{\n\tisCurrentRiotInfoSet = false;\n\n\tleague = info;\n\n\tif (league.port == 0 || league.token.empty())\n\t\treturn false;\n\n\tleague.header = Auth::MakeLeagueHeader(info);\n\n\tsession = cpr::Session();\n\tsession.SetVerifySsl(false);\n\n\tsession.SetHeader(Utils::StringToHeader(league.header));\n\n\treturn true;\n}\n\nbool LCU::SetLeagueClientInfo()\n{\n\tif (!IsProcessGood())\n\t\treturn false;\n\treturn SetLeagueClientInfo(Auth::GetClientInfo(leagueProcesses[indexLeagueProcesses].first));\n}\n\nbool LCU::SetCurrentClientRiotInfo()\n{\n\tif (isCurrentRiotInfoSet)\n\t\treturn true;\n\n\tconst bool isSet = SetRiotClientInfo(Auth::GetClientInfo(leagueProcesses[indexLeagueProcesses].first, true));\n\tif (isSet)\n\t\tisCurrentRiotInfoSet = true;\n\n\treturn isSet;\n}\n\nvoid LCU::GetLeagueProcesses()\n{\n\tconst std::vector<DWORD> allProcessIds = Auth::GetAllProcessIds(L\"LeagueClientUx.exe\");\n\t// remove unexisting clients\n\tfor (size_t i = 0; i < leagueProcesses.size(); i++)\n\t{\n\t\tbool exists = false;\n\t\tfor (const DWORD& proc : allProcessIds)\n\t\t{\n\t\t\tif (proc == leagueProcesses[i].first)\n\t\t\t{\n\t\t\t\texists = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!exists)\n\t\t{\n\t\t\tleagueProcesses.erase(leagueProcesses.begin() + i);\n\t\t\tif (i == indexLeagueProcesses)\n\t\t\t\tSetLeagueClientInfo();\n\t\t}\n\t}\n\n\tfor (const DWORD& proc : allProcessIds)\n\t{\n\t\tint foundIndex = -1;\n\t\tfor (size_t i = 0; i < leagueProcesses.size(); i++)\n\t\t{\n\t\t\tif (leagueProcesses[i].first == proc)\n\t\t\t{\n\t\t\t\tfoundIndex = static_cast<int>(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (foundIndex != -1 && !leagueProcesses[foundIndex].second.empty())\n\t\t\tcontinue;\n\n\t\tClientInfo currentInfo = Auth::GetClientInfo(proc);\n\t\tcurrentInfo.header = Auth::MakeLeagueHeader(currentInfo);\n\n\t\tsize_t currentIndex = foundIndex;\n\t\tif (foundIndex == -1)\n\t\t{\n\t\t\tcurrentIndex = leagueProcesses.size();\n\t\t\tstd::pair<DWORD, std::string> temp = { proc, \"\" };\n\t\t\tleagueProcesses.emplace_back(temp);\n\t\t}\n\n\t\tstd::thread t([currentIndex, currentInfo]() {\n\t\t\tshort sessionFailCount = 0;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tcpr::Session session;\n\t\t\t\tsession.SetVerifySsl(false);\n\t\t\t\tsession.SetHeader(Utils::StringToHeader(currentInfo.header));\n\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-login/v1/session\", currentInfo.port));\n\t\t\t\tstd::string procSession = session.Get().text;\n\n\t\t\t\t// probably legacy client\n\t\t\t\tif (procSession.find(\"errorCode\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tsessionFailCount++;\n\t\t\t\t\tif (sessionFailCount > 5)\n\t\t\t\t\t{\n\t\t\t\t\t\tleagueProcesses[currentIndex].second = \"!FAILED!\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(300));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\n\t\t\t\tif (reader->parse(procSession.c_str(), procSession.c_str() + static_cast<int>(procSession.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tstd::string currentSummId = root[\"summonerId\"].asString();\n\t\t\t\t\t// player has summId when client is loaded\n\t\t\t\t\tif (!currentSummId.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/lol-summoner/v1/summoners/{}\", currentInfo.port, currentSummId));\n\t\t\t\t\t\tstd::string currentSummoner = session.Get().text;\n\n\t\t\t\t\t\tif (reader->parse(currentSummoner.c_str(), currentSummoner.c_str() + static_cast<int>(currentSummoner.length()), &root, &err))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tleagueProcesses[currentIndex].second = std::string(root[\"gameName\"].asString().substr(0, 25)) + \"#\" + std::string(root[\"tagLine\"].asString());\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(300));\n\t\t\t}\n\t\t\t});\n\t\tt.detach();\n\t}\n}\n\nbool LCU::IsProcessGood()\n{\n\treturn !leagueProcesses.empty() && indexLeagueProcesses < leagueProcesses.size();\n}\n\n// TODO: sync with LCU header, it's almost the same\nstd::string LCU::GetStoreHeader()\n{\n\tstd::string storeUrl = Request(\"GET\", \"/lol-store/v1/getStoreUrl\");\n\tstd::erase(storeUrl, '\"');\n\n\tstd::string accessToken = Request(\"GET\", \"/lol-rso-auth/v1/authorization/access-token\");\n\tJson::CharReaderBuilder builder;\n\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\tJSONCPP_STRING err;\n\tJson::Value root;\n\tif (reader->parse(accessToken.c_str(), accessToken.c_str() + static_cast<int>(accessToken.length()), &root, &err))\n\t{\n\t\tstd::string storeToken = root[\"token\"].asString();\n\t\tstd::string storeHost;\n\t\tif (auto n = storeUrl.find(\"https://\"); n != std::string::npos)\n\t\t{\n\t\t\tstoreHost = storeUrl.substr(n + strlen(\"https://\"));\n\t\t}\n\t\tstd::string storeHeader = \"Host: \" + storeHost + \"\\r\\n\" +\n\t\t\t\"Connection: keep-alive\\r\\n\" +\n\t\t\t\"AUTHORIZATION: Bearer \" + storeToken + \"\\r\\n\" +\n\t\t\t\"Accept: application/json\" + \"\\r\\n\" +\n\t\t\t\"Accept-Language: en-US,en;q=0.9\" + \"\\r\\n\" +\n\t\t\t\"Content-Type: application/json\" + \"\\r\\n\" +\n\t\t\t\"Origin: https://127.0.0.1:\" + std::to_string(league.port) + \"\\r\\n\" +\n\t\t\t\"User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) LeagueOfLegendsClient/\" + league.version +\n\t\t\t\" (CEF 91) Safari/537.36\" + \"\\r\\n\" +\n\t\t\t//X-B3-SpanId:\n\t\t\t//X-B3-TraceId:\n\t\t\tR\"(sec-ch-ua: \"Chromium\";v=\"91\")\" + \"\\r\\n\" +\n\t\t\t\"sec-ch-ua-mobile: ?0\" + \"\\r\\n\" +\n\t\t\t\"Sec-Fetch-Site: same-origin\" + \"\\r\\n\" +\n\t\t\t\"Sec-Fetch-Mode: no-cors\" + \"\\r\\n\" +\n\t\t\t\"Sec-Fetch-Dest: empty\" + \"\\r\\n\" +\n\t\t\t\"Referer: https://127.0.0.1:\" + std::to_string(league.port) + \"\\r\\n\" +\n\t\t\t\"Accept-Encoding: \"/*gzip,*/ + \"deflate, br\";\n\t\treturn storeHeader;\n\t}\n\n\treturn \"\";\n}\n\n/**\n * \\brief Fixes Wininet error 12158, #80 in GitHub issues\n */\nstatic void FixCachingProblem()\n{\n\tusing tRegOpenKeyExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,\n\t\tREGSAM samDesired, PHKEY phkResult);\n\tstatic auto RegOpenKeyExA = reinterpret_cast<tRegOpenKeyExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegOpenKeyExA\"));\n\n\tusing tRegQueryValueExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpValueName,\n\t\tLPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbDatan);\n\tstatic auto RegQueryValueExA = reinterpret_cast<tRegQueryValueExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegQueryValueExA\"));\n\n\tusing tRegSetValueExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpValueName, DWORD Reserved,\n\t\tDWORD dwType, const BYTE* lpData, DWORD cbData);\n\tstatic auto RegSetValueExA = reinterpret_cast<tRegSetValueExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegSetValueExA\"));\n\n\tusing tRegCloseKey = LSTATUS(WINAPI*)(HKEY hKe);\n\tstatic auto RegCloseKey = reinterpret_cast<tRegCloseKey>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegCloseKey\"));\n\n\tbool bChanged = false;\n\tHKEY hkResult;\n\tif (RegOpenKeyExA(HKEY_LOCAL_MACHINE, R\"(Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings)\", 0, KEY_READ | KEY_WRITE,\n\t\t&hkResult) == ERROR_SUCCESS)\n\t{\n\t\tDWORD value;\n\t\tDWORD newValue = 0;\n\t\tDWORD dwSize = sizeof(value);\n\t\tif (const LSTATUS regQuery = RegQueryValueExA(hkResult, \"DisableCachingOfSSLPages\", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value),\n\t\t\t&dwSize); regQuery == ERROR_SUCCESS)\n\t\t{\n\t\t\tif (value == 0x1)\n\t\t\t{\n\t\t\t\tRegSetValueExA(hkResult, \"DisableCachingOfSSLPages\", 0, REG_DWORD, reinterpret_cast<LPBYTE>(&newValue), dwSize);\n\t\t\t\tbChanged = true;\n\t\t\t}\n\t\t}\n\t\telse if (regQuery == ERROR_FILE_NOT_FOUND) // if key doesnt exist, create it\n\t\t{\n\t\t\tRegSetValueExA(hkResult, \"DisableCachingOfSSLPages\", 0, REG_DWORD, reinterpret_cast<LPBYTE>(&newValue), dwSize);\n\t\t\tbChanged = true;\n\t\t}\n\t\tRegCloseKey(hkResult);\n\t}\n\n\tif (bChanged == true)\n\t{\n\t\tMessageBoxA(nullptr, \"Restart the program\\n\\nIf this pop-up window keeps showing up: Open \\\"Internet Options\\\", \"\n\t\t\t\"Go to \\\"Advanced\\\" tab and disable \\\"Do not save encrypted pages to disk\\\". Press \\\"Apply\\\" and \\\"OK\\\"\",\n\t\t\t\"Updated faulty options\", MB_OK);\n\t\texit(EXIT_SUCCESS); // ConcurrencyMtUnsafe)\n\t}\n}"
  },
  {
    "path": "KBotExt/LCU.h",
    "content": "#pragma once\n\n#include <cpr/cpr.h>\n\n#include \"Definitions.h\"\n#include \"Auth.h\"\n\nclass LCU\n{\npublic:\n\tstatic inline cpr::Session session;\n\n\tstatic inline ClientInfo league;\n\tstatic inline ClientInfo riot;\n\n\tstatic std::string Request(const std::string& method, const std::string& endpoint, const std::string& body = \"\");\n\n\tstatic bool SetRiotClientInfo(const ClientInfo& info);\n\tstatic bool SetRiotClientInfo();\n\n\tstatic bool SetLeagueClientInfo(const ClientInfo& info);\n\tstatic bool SetLeagueClientInfo();\n\n\tstatic bool SetCurrentClientRiotInfo();\n\n\tstatic inline std::vector<std::pair<DWORD, std::string>> leagueProcesses;\n\tstatic inline size_t indexLeagueProcesses = 0; // currently selected process\n\tstatic void GetLeagueProcesses();\n\tstatic bool IsProcessGood();\n\n\tstatic std::string GetStoreHeader();\n\nprivate:\n\tstatic inline bool isCurrentRiotInfoSet = false;\n};\n"
  },
  {
    "path": "KBotExt/LoginTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"Utils.h\"\n#include \"LCU.h\"\n#include \"Misc.h\"\n#include \"Config.h\"\n\n#pragma warning(disable : 4996)\n\nclass LoginTab\n{\n\tstatic void LoginOnClientOpen(const std::string& username, const std::string& password)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tif (FindWindowA(NULL, \"Riot Client\") && LCU::riot.port != 0)\n\t\t\t{\n\t\t\t\t// waits to be sure that client is fully loaded\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(2000));\n\t\t\t\tLogin(username, password);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t}\n\t}\n\n\tstatic std::string Login(std::string username, std::string password)\n\t{\n\t\t// If riot client not open\n\t\tif (LCU::riot.port == 0)\n\t\t{\n\t\t\tif (std::filesystem::exists(S.leaguePath))\n\t\t\t{\n\t\t\t\tMisc::LaunchClient(\"\");\n\t\t\t\tstd::thread t(LoginOnClientOpen, username, password);\n\t\t\t\tt.detach();\n\t\t\t\treturn \"Launching client...\";\n\t\t\t}\n\t\t\treturn \"Invalid client path, change it in Settings tab\";\n\t\t}\n\n\t\tcpr::Session session;\n\t\tsession.SetVerifySsl(false);\n\t\tsession.SetHeader(Utils::StringToHeader(LCU::riot.header));\n\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/rso-auth/v2/authorizations\", LCU::riot.port));\n\t\tsession.SetBody(R\"({\"clientId\":\"riot-client\",\"trustLevels\":[\"always_trusted\"]})\");\n\t\tsession.Post();\n\t\t// refresh session\n\n\t\tconst std::string loginBody = R\"({\"username\":\")\" + username + R\"(\",\"password\":\")\" + password + R\"(\",\"persistLogin\":false})\";\n\t\tsession.SetUrl(std::format(\"https://127.0.0.1:{}/rso-auth/v1/session/credentials\", LCU::riot.port));\n\t\tsession.SetBody(loginBody);\n\t\tstd::string result = session.Put().text;\n\n\t\tconst Json::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t{\n\t\t\tif (!root[\"type\"].empty())\n\t\t\t\treturn root[\"type\"].asString();\n\t\t\tif (!root[\"message\"].empty())\n\t\t\t\treturn root[\"message\"].asString();\n\t\t}\n\t\treturn result;\n\t}\n\npublic:\n\tstatic void Render()\n\t{\n\t\tif (ImGui::BeginTabItem(\"Login\"))\n\t\t{\n\t\t\tstatic std::string result;\n\t\t\tstatic bool once = true;\n\t\t\tstatic char leagueArgs[1024 * 16];\n\t\t\tstatic std::string sArgs;\n\n\t\t\tif (once)\n\t\t\t{\n\t\t\t\tonce = false;\n\t\t\t\tstd::ranges::copy(S.loginTab.leagueArgs, leagueArgs);\n\t\t\t}\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tstatic std::vector<std::pair<std::string, std::string>> langs = {\n\t\t\t\t{\"English (US)\", \"en_US\"}, {\"Japanese\", \"ja_JP\"}, {\"Korean\", \"ko_KR\"}, {\"Chinese (China)\", \"zh_CN\"},\n\t\t\t\t{\"German\", \"de_DE\"}, {\"Spanish (Spain)\", \"es_ES\"}, {\"Polish\", \"pl_PL\"}, {\"Russian\", \"ru_RU\"},\n\t\t\t\t{\"French\", \"fr_FR\"}, {\"Turkish\", \"tr_TR\"}, {\"Portuguese\", \"pt_BR\"}, {\"Czech\", \"cs_CZ\"}, {\"Greek\", \"el_GR\"},\n\t\t\t\t{\"Romanian\", \"ro_RO\"}, {\"Hungarian\", \"hu_HU\"}, {\"English (UK)\", \"en_GB\"}, {\"Italian\", \"it_IT\"},\n\t\t\t\t{\"Spanish (Mexico)\", \"es_MX\"}, {\"Spanish (Argentina)\", \"es_AR\"}, {\"English (Australia)\", \"en_AU\"},\n\t\t\t\t{\"Malay\", \"ms_MY\"}, {\"English (Philippines)\", \"en_PH\"}, {\"English (Singapore)\", \"en_SG\"}, {\"Thai\", \"th_TH\"},\n\t\t\t\t{\"Vietnamese\", \"vi_VN\"}, {\"Indonesian\", \"id_ID\"}, {\"Tagalog\", \"tl_PH\"}, {\"Chinese (Malaysia)\", \"zh_MY\"}, {\"Chinese (Taiwan)\", \"zh_TW\"}\n\t\t\t};\n\t\t\t// find saved lang from cfg file\n\t\t\tauto findLang = std::ranges::find_if(langs, [](std::pair<std::string, std::string> k) {\n\t\t\t\treturn k.second == S.loginTab.language;\n\t\t\t\t});\n\n\t\t\tstatic std::pair selectedLang = { findLang[0].first, findLang[0].second };\n\n\t\t\tif (ImGui::Button(\"Launch client\"))\n\t\t\t{\n\t\t\t\tif (!std::filesystem::exists(S.leaguePath))\n\t\t\t\t{\n\t\t\t\t\tresult = \"Invalid path, change it in Settings tab\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tMisc::LaunchClient(sArgs);\n\t\t\t\t\tresult = S.leaguePath + \"LeagueClient.exe \" + sArgs;\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::BeginCombo(\"##language\", selectedLang.first.c_str()))\n\t\t\t{\n\t\t\t\tfor (const auto& [fst, snd] : langs)\n\t\t\t\t{\n\t\t\t\t\tif (ImGui::Selectable(fst.c_str(), fst == selectedLang.first))\n\t\t\t\t\t{\n\t\t\t\t\t\tselectedLang = { fst, snd };\n\t\t\t\t\t\tS.loginTab.language = snd;\n\t\t\t\t\t\tConfig::Save();\n\n\t\t\t\t\t\tstd::string localeArg = std::format(\"--locale={} \", selectedLang.second);\n\t\t\t\t\t\tsize_t localePos = sArgs.find(\"--locale=\");\n\t\t\t\t\t\tif (localePos != std::string::npos)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsArgs.replace(localePos, localeArg.size(), localeArg);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsArgs += localeArg;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Launch legacy client\"))\n\t\t\t{\n\t\t\t\tif (!std::filesystem::exists(S.leaguePath))\n\t\t\t\t{\n\t\t\t\t\tresult = \"Invalid path, change it in Settings tab\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tMisc::LaunchLegacyClient();\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::Columns(1);\n\n\t\t\tstd::ranges::copy(sArgs, leagueArgs);\n\t\t\tImGui::Text(\" Args: \");\n\t\t\tImGui::SameLine();\n\t\t\tImGui::InputText(\"##inputLeagueArgs\", leagueArgs, IM_ARRAYSIZE(leagueArgs));\n\n\t\t\tsArgs = leagueArgs;\n\t\t\tS.loginTab.leagueArgs = sArgs;\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic char username[128];\n\t\t\tImGui::Text(\"Username:\");\n\t\t\tImGui::InputText(\"##inputUsername\", username, IM_ARRAYSIZE(username));\n\n\t\t\tstatic char password[128];\n\t\t\tImGui::Text(\"Password:\");\n\t\t\tImGui::InputText(\"##inputPassword\", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);\n\n\t\t\tif (ImGui::Button(\"Login\") || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter), false))\n\t\t\t{\n\t\t\t\tif (!std::string(username).empty() && !std::string(password).empty())\n\t\t\t\t\tresult = Login(username, password);\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Save\") && !std::string(username).empty() && !std::string(password).empty())\n\t\t\t{\n\t\t\t\t// if file doesn't exist, create new one with {} so it can be parsed\n\t\t\t\tif (!std::filesystem::exists(S.settingsFile))\n\t\t\t\t{\n\t\t\t\t\tstd::ofstream file(S.settingsFile);\n\t\t\t\t\tfile << \"{}\";\n\t\t\t\t\tfile.close();\n\t\t\t\t}\n\n\t\t\t\tstd::ifstream iFile(S.settingsFile);\n\n\t\t\t\tif (iFile.good())\n\t\t\t\t{\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\t/** \\\n\t\t\t\t\t* \\deprecated Use CharReader and CharReaderBuilder.\n\t\t\t\t\t*/\n\t\t\t\t\tif (Json::Reader reader; reader.parse(iFile, root, false))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!root[\"accounts\"].isArray())\n\t\t\t\t\t\t\troot[\"accounts\"] = Json::Value(Json::arrayValue);\n\t\t\t\t\t\tJson::Value accArray = root[\"accounts\"];\n\n\t\t\t\t\t\taccArray.append(std::format(\"{0}:{1}\", username, password));\n\t\t\t\t\t\troot[\"accounts\"] = accArray;\n\n\t\t\t\t\t\tstd::ofstream oFile(S.settingsFile);\n\t\t\t\t\t\toFile << root.toStyledString() << std::endl;\n\t\t\t\t\t\toFile.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tiFile.close();\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\n\t\t\t\t\"This part is only, if you want to save your login and pass to config file and login with 1 click. You don't have to do that, you can just log in the usual way in client and launch the tool anytime you want\");\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Columns(2, nullptr, false);\n\t\t\tImGui::NextColumn();\n\n\t\t\tstatic std::string banCheck;\n\n\t\t\tif (ImGui::Button(\"Check ban reason\"))\n\t\t\t{\n\t\t\t\tJson::Value authData;\n\t\t\t\tauthData[\"acr_values\"] = \"\";\n\t\t\t\tauthData[\"claims\"] = \"\";\n\t\t\t\tauthData[\"client_id\"] = \"riot-client\";\n\t\t\t\tauthData[\"nonce\"] = Utils::RandomString(22);\n\t\t\t\tauthData[\"code_challenge\"] = \"\";\n\t\t\t\tauthData[\"code_challenge_method\"] = \"\";\n\t\t\t\tauthData[\"redirect_uri\"] = \"http://localhost/redirect\";\n\t\t\t\tauthData[\"response_type\"] = \"token id_token\";\n\t\t\t\tauthData[\"scope\"] = \"openid offline_access lol ban profile email phone birthdate summoner link lol_region\";\n\n\t\t\t\tcpr::Header authHeader = {\n\t\t\t\t\t{\"Content-Type\", \"application/json\"},\n\t\t\t\t\t{\"Accept-Encoding\", \"deflate\"},\n\t\t\t\t\t{\"User-Agent\", \"RiotClient/69.0.3.228.1352 rso-auth (Windows;10;;Home, x64)\"},\n\t\t\t\t\t{\"Pragma\", \"no-cache\"},\n\t\t\t\t\t{\"Accept-Language\", \"en-GB,en,*\"},\n\t\t\t\t\t{\"Accept\", \"application/json, text/plain, */*\"}\n\t\t\t\t};\n\n\t\t\t\tcpr::Session session;\n\t\t\t\tsession.SetHeader(authHeader);\n\n\t\t\t\tstd::string valoApi = cpr::Get(cpr::Url{ \"https://valorant-api.com/v1/version\" }).text;\n\n\t\t\t\tstd::regex regexStr(\"\\\"riotClientBuild\\\":\\\"(.*?)\\\"\");\n\t\t\t\tif (std::smatch m; std::regex_search(valoApi, m, regexStr))\n\t\t\t\t{\n\t\t\t\t\tsession.UpdateHeader(cpr::Header{ {\"User-Agent\", \"RiotClient/\" + m[1].str() + \" rso-auth (Windows;10;;Home, x64)\"} });\n\t\t\t\t}\n\n\t\t\t\tsession.SetBody(authData.toStyledString());\n\t\t\t\tsession.SetUrl(\"https://auth.riotgames.com/api/v1/authorization\");\n\t\t\t\tsession.Post();\n\n\t\t\t\tJson::Value authData2;\n\t\t\t\tauthData2[\"language\"] = \"en_GB\";\n\t\t\t\tauthData2[\"password\"] = password;\n\t\t\t\tauthData2[\"region\"] = Json::nullValue;\n\t\t\t\tauthData2[\"remember\"] = false;\n\t\t\t\tauthData2[\"type\"] = \"auth\";\n\t\t\t\tauthData2[\"username\"] = username;\n\n\t\t\t\tsession.SetBody(authData2.toStyledString());\n\t\t\t\tsession.SetUrl(\"https://auth.riotgames.com/api/v1/authorization\");\n\t\t\t\tstd::string r = session.Put().text;\n\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value rootAuth;\n\t\t\t\tbanCheck = r;\n\t\t\t\tif (r.find(\"\\\"error\\\"\") == std::string::npos && reader->parse(r.c_str(), r.c_str() + static_cast<int>(r.length()), &rootAuth, &err))\n\t\t\t\t{\n\t\t\t\t\tstd::string uri = rootAuth[\"response\"][\"parameters\"][\"uri\"].asString();\n\t\t\t\t\tsize_t startIndex = uri.find(\"#access_token=\") + strlen(\"#access_token=\");\n\t\t\t\t\tsize_t endIndex = uri.find(\"&scope\");\n\t\t\t\t\tstd::string bearer = uri.substr(startIndex, endIndex - startIndex);\n\t\t\t\t\tsession.UpdateHeader(cpr::Header{ {\"Authorization\", \"Bearer \" + bearer} });\n\n\t\t\t\t\tsession.SetUrl(\"https://auth.riotgames.com/userinfo\");\n\t\t\t\t\tr = session.Get().text;\n\t\t\t\t\tJson::Value rootInfo;\n\n\t\t\t\t\tif (reader->parse(r.c_str(), r.c_str() + static_cast<int>(r.length()), &rootInfo, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tbanCheck = rootInfo.toStyledString();\n\t\t\t\t\t\tstd::cout << rootInfo.toStyledString();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Get email\"))\n\t\t\t{\n\t\t\t\tMessageBoxA(nullptr, \"Login\\nClick on 'My Tickets'\\nCtrl+Shift+I\\nCtrl+F and search for \\\"email\\\"\", \"Info\", MB_OK | MB_SETFOREGROUND);\n\n\t\t\t\tUtils::OpenUrl(L\"https://auth.riotgames.com/authorize?redirect_uri=https://login.playersupport.riotgames.com/login_callback&client_id=player-support-zendesk&ui_locales=en-us%20en-us&response_type=code&scope=openid%20email\"\n\t\t\t\t\t, nullptr, SW_SHOW);\n\n\t\t\t\t// Outdated, new login endpoints require captcha\n\t\t\t\t//\n\t\t\t\t//cpr::Session session;\n\t\t\t\t//cpr::Header authHeader = {\n\t\t\t\t//\t{\"Content-Type\", \"application/json\"},\n\t\t\t\t//\t{\"Accept-Encoding\", \"deflate\"},\n\t\t\t\t//\t{\"Upgrade-Insecure-Requests\", \"1\"},\n\t\t\t\t//\t{\"sec-ch-ua\", R\"(\"Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"115\", \"Chromium\";v=\"115\")\"},\n\t\t\t\t//\t{\"sec-ch-ua-platform\", \"\\\"Windows\\\"\"},\n\t\t\t\t//\t{\"sec-ch-ua-mobile\", \"?0\"},\n\t\t\t\t//\t{\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36\"},\n\t\t\t\t//\t{\"Sec-Fetch-Site\", \"cross-site\"},\n\t\t\t\t//\t{\"Sec-Fetch-Mode\", \"navigate\"},\n\t\t\t\t//\t{\"Sec-Fetch-Dest\", \"document\"},\n\t\t\t\t//\t{\"Accept-Language\", \"en-US,en;q=0.9\"},\n\t\t\t\t//\t{\n\t\t\t\t//\t\t\"Accept\",\n\t\t\t\t//\t\t\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\"\n\t\t\t\t//\t},\n\t\t\t\t//\t{\"Referer\", \"https://riotgames.zendesk.com/\"},\n\t\t\t\t//};\n\t\t\t\t//session.SetHeader(authHeader);\n\n\t\t\t\t//session.SetUrl(\n\t\t\t\t//\t\"https://auth.riotgames.com/authorize?redirect_uri=https://login.playersupport.riotgames.com/login_callback&client_id=player-support-zendesk&ui_locales=en-us%20en-us&response_type=code&scope=openid%20email\");\n\t\t\t\t//session.Get();\n\n\t\t\t\t//Json::Value authData2;\n\t\t\t\t//authData2[\"language\"] = \"en_GB\";\n\t\t\t\t//authData2[\"password\"] = password;\n\t\t\t\t//authData2[\"region\"] = Json::nullValue;\n\t\t\t\t//authData2[\"remember\"] = false;\n\t\t\t\t//authData2[\"type\"] = \"auth\";\n\t\t\t\t//authData2[\"username\"] = username;\n\n\t\t\t\t//session.SetBody(authData2.toStyledString());\n\t\t\t\t//session.SetUrl(\"https://auth.riotgames.com/api/v1/authorization\");\n\t\t\t\t//std::string r = session.Put().text;\n\n\t\t\t\t//Json::CharReaderBuilder builder;\n\t\t\t\t//const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t//JSONCPP_STRING err;\n\t\t\t\t//Json::Value rootAuth;\n\t\t\t\t//banCheck = r;\n\t\t\t\t//if (r.find(\"\\\"error\\\"\") == std::string::npos && reader->parse(r.c_str(), r.c_str() + static_cast<int>(r.length()), &rootAuth, &err))\n\t\t\t\t//{\n\t\t\t\t//\tsession.SetUrl(rootAuth[\"response\"][\"parameters\"][\"uri\"].asString());\n\t\t\t\t//\tsession.Get().text; // UnusedValue\n\n\t\t\t\t//\tsession.SetUrl(\"https://support-leagueoflegends.riotgames.com/hc/en-us/requests\");\n\t\t\t\t//\tstd::string support = session.Get().text;\n\t\t\t\t//\tstd::regex regexStr(\"\\\"email\\\":(.*?),\");\n\t\t\t\t//\tif (std::smatch m; std::regex_search(support, m, regexStr))\n\t\t\t\t//\t{\n\t\t\t\t//\t\tbanCheck = m.str();\n\t\t\t\t//\t}\n\t\t\t\t//}\n\t\t\t}\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tstd::ifstream iFile(S.settingsFile);\n\n\t\t\tif (iFile.good())\n\t\t\t{\n\t\t\t\tJson::Value root;\n\t\t\t\t/** \\\n\t\t\t\t* \\deprecated Use CharReader and CharReaderBuilder.\n\t\t\t\t*/\n\t\t\t\tif (Json::Reader reader; reader.parse(iFile, root, false))\n\t\t\t\t{\n\t\t\t\t\tif (auto accArray = root[\"accounts\"]; accArray.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (Json::Value::ArrayIndex i = 0; i < accArray.size(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::string acc = accArray[i].asString();\n\t\t\t\t\t\t\tstd::string accUsername = acc.substr(0, acc.find(':'));\n\t\t\t\t\t\t\tstd::string accPassword = acc.substr(acc.find(':') + 1);\n\t\t\t\t\t\t\tif (ImGui::Button(accUsername.c_str()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tresult = Login(accUsername, accPassword);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tImGui::SameLine();\n\t\t\t\t\t\t\tstd::string deleteButton = \"Delete##\" + acc;\n\t\t\t\t\t\t\tif (ImGui::Button(deleteButton.c_str()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::ofstream oFile(S.settingsFile);\n\t\t\t\t\t\t\t\taccArray.removeIndex(i, nullptr);\n\t\t\t\t\t\t\t\troot[\"accounts\"] = accArray;\n\t\t\t\t\t\t\t\toFile << root.toStyledString() << std::endl;\n\t\t\t\t\t\t\t\toFile.close();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tiFile.close();\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tImGui::TextWrapped(banCheck.c_str());\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::TextWrapped(result.c_str());\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t}\n};\n"
  },
  {
    "path": "KBotExt/Misc.h",
    "content": "#pragma once\n\n#include <fstream>\n#include <thread>\n#include <filesystem>\n#include <tlhelp32.h>\n#include \"LCU.h\"\n#include \"Config.h\"\n\n#include \"imgui_internal.h\"\n\n#ifdef _MSC_VER\n#include <Shlwapi.h>\n#define ISTRSTR StrStrIA\n#pragma comment(lib, \"Shlwapi.lib\")\n#else\n#define ISTRSTR strcasestr\n#endif\n\nclass Misc\n{\npublic:\n\tstatic inline std::string programVersion = \"1.5.6\";\n\tstatic inline std::string latestVersion;\n\n\tstatic bool LaunchClient(const std::string& args)\n\t{\n\t\tconst std::string path = std::format(\"{}LeagueClient.exe\", S.leaguePath);\n\t\tif (S.noAdmin)\n\t\t{\n\t\t\tif (Utils::RunAsUser(Utils::StringToWstring(path).c_str(), Utils::StringToWstring(args).data()))\n\t\t\t\treturn true;\n\t\t}\n\t\tUtils::OpenUrl(path.c_str(), args.c_str(), SW_SHOWNORMAL);\n\t\treturn false;\n\t}\n\n\tstatic void LaunchLegacyClient()\n\t{\n\t\tif (!std::filesystem::exists(std::format(\"{}LoL Companion\", S.leaguePath)))\n\t\t{\n\t\t\tstd::filesystem::create_directory(std::format(\"{}LoL Companion\", S.leaguePath));\n\t\t}\n\t\tif (!std::filesystem::exists(std::format(\"{}LoL Companion/system.yaml\", S.leaguePath)))\n\t\t{\n\t\t\tstd::ifstream infile(std::format(\"{}system.yaml\", S.leaguePath));\n\t\t\tstd::ofstream outfile(std::format(\"{}LoL Companion/system.yaml\", S.leaguePath));\n\t\t\tstd::string content;\n\n\t\t\tstd::string temp;\n\t\t\twhile (std::getline(infile, temp))\n\t\t\t\tcontent += temp + \"\\n\";\n\n\t\t\tinfile.close();\n\t\t\tsize_t pos = content.find(\"riotclient:\");\n\t\t\tcontent = content.substr(0, pos + 11);\n\n\t\t\toutfile << content;\n\t\t\toutfile.close();\n\t\t}\n\n\t\tif (FindWindowA(\"RCLIENT\", \"League of Legends\"))\n\t\t{\n\t\t\tLCU::Request(\"POST\", \"https://127.0.0.1/process-control/v1/process/quit\");\n\n\t\t\t// wait for client to close (maybe there's a better method of doing that)\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(4500));\n\t\t}\n\n\t\tUtils::OpenUrl(std::format(\"{}LeagueClient.exe\", S.leaguePath).c_str(),\n\t\t\tstd::format(\"--system-yaml-override=\\\"{}LoL Companion/system.yaml\\\"\", S.leaguePath).c_str(), SW_SHOWNORMAL);\n\t}\n\n\tstatic void CheckVersion()\n\t{\n\t\tconst std::string getLatest = cpr::Get(cpr::Url{ \"https://api.github.com/repos/KebsCS/KBotExt/releases/latest\" }).text;\n\n\t\tif (getLatest.contains(\"API rate limit\"))\n\t\t\treturn;\n\n\t\tconst Json::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(getLatest.c_str(), getLatest.c_str() + static_cast<int>(getLatest.length()), &root, &err))\n\t\t{\n\t\t\tstd::string latestTag = root[\"tag_name\"].asString();\n\t\t\tlatestVersion = latestTag;\n\n\t\t\tconst std::vector<std::string> latestNameSplit = Utils::StringSplit(latestTag, \".\");\n\t\t\tconst std::vector<std::string> programVersionSplit = Utils::StringSplit(programVersion, \".\");\n\n\t\t\tfor (size_t i = 0; i < 2; i++)\n\t\t\t{\n\t\t\t\tif (latestNameSplit[i] != programVersionSplit[i])\n\t\t\t\t{\n\t\t\t\t\tif (MessageBoxA(nullptr, \"Open download website?\", \"New major version available\", MB_YESNO | MB_SETFOREGROUND) == IDYES)\n\t\t\t\t\t{\n\t\t\t\t\t\tUtils::OpenUrl(L\"https://github.com/KebsCS/KBotExt/releases/latest\", nullptr, SW_SHOW);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (latestTag != programVersion\n\t\t\t\t&& std::ranges::find(S.ignoredVersions, latestTag) == S.ignoredVersions.end())\n\t\t\t{\n\t\t\t\tif (const auto status = MessageBoxA(nullptr, \"Open download website?\\nCancel to ignore this version forever\",\n\t\t\t\t\t\"New minor update available\", MB_YESNOCANCEL | MB_SETFOREGROUND); status == IDYES)\n\t\t\t\t{\n\t\t\t\t\tUtils::OpenUrl(L\"https://github.com/KebsCS/KBotExt/releases/latest\", nullptr, SW_SHOW);\n\t\t\t\t}\n\t\t\t\telse if (status == IDCANCEL)\n\t\t\t\t{\n\t\t\t\t\tS.ignoredVersions.emplace_back(latestTag);\n\t\t\t\t\tConfig::Save();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void CheckPrerelease(std::string newName = \"\")\n\t{\n\t\tconst std::string getPrerelease = cpr::Get(cpr::Url{ \"https://api.github.com/repos/KebsCS/KBotExt/releases/tags/prerelease\" }).text;\n\n\t\tif (getPrerelease.contains(\"API rate limit\"))\n\t\t\treturn;\n\n\t\tconst Json::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(getPrerelease.c_str(), getPrerelease.c_str() + static_cast<int>(getPrerelease.length()), &root, &err))\n\t\t{\n\t\t\tif (root.isMember(\"assets\") && root[\"assets\"].isArray() && !root[\"assets\"].empty())\n\t\t\t{\n\t\t\t\tstd::string updatedAt = root[\"assets\"][0][\"updated_at\"].asString();\n\t\t\t\tstd::tm dateTm;\n\t\t\t\tstd::istringstream dateStream(updatedAt);\n\t\t\t\tdateStream >> std::get_time(&dateTm, \"%Y-%m-%dT%H:%M:%SZ\");\n\t\t\t\tstd::time_t githubUpdatedTime = std::mktime(&dateTm);\n\n\t\t\t\tchar szExeFileName[MAX_PATH];\n\t\t\t\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\t\t\t\tstatic auto pGetModuleFileNameA = (decltype(&GetModuleFileNameA))GetProcAddress(kernel32, \"GetModuleFileNameA\");\n\t\t\t\tpGetModuleFileNameA(nullptr, szExeFileName, MAX_PATH);\n\t\t\t\tstd::string path = std::string(szExeFileName);\n\n\t\t\t\tif (newName != \"\")\n\t\t\t\t\tpath = path.substr(0, path.find_last_of('\\\\') + 1) + newName;\n\n\t\t\t\tconst std::filesystem::file_time_type lastWriteTime = std::filesystem::last_write_time(path);\n\t\t\t\tconst auto systemTime = std::chrono::clock_cast<std::chrono::system_clock>(lastWriteTime);\n\t\t\t\tconst std::time_t localUpdatedTime = std::chrono::system_clock::to_time_t(systemTime);\n\n\t\t\t\tif (githubUpdatedTime > localUpdatedTime)\n\t\t\t\t{\n\t\t\t\t\tif (MessageBoxA(nullptr, \"Open download website?\", \"New prerelease available\", MB_YESNO | MB_SETFOREGROUND) == IDYES)\n\t\t\t\t\t{\n\t\t\t\t\t\tUtils::OpenUrl(L\"https://github.com/KebsCS/KBotExt/releases/tag/prerelease\", nullptr, SW_SHOW);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic std::string GetCurrentPatch()\n\t{\n\t\tconst std::string result = cpr::Get(cpr::Url{ \"http://ddragon.leagueoflegends.com/api/versions.json\" }).text;\n\t\tconst Json::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t{\n\t\t\treturn root[0].asString();\n\t\t}\n\t\treturn \"0.0.0\";\n\t}\n\n\tstatic void GetAllChampionSkins()\n\t{\n\t\tstd::string getSkins = cpr::Get(cpr::Url{ \"https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/skins.json\" }).text;\n\t\tJson::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (!reader->parse(getSkins.c_str(), getSkins.c_str() + static_cast<int>(getSkins.length()), &root, &err))\n\t\t\treturn;\n\n\t\tstd::map<std::string, Champ> champs;\n\t\tfor (const std::string& id : root.getMemberNames())\n\t\t{\n\t\t\tconst Json::Value currentSkin = root[id];\n\n\t\t\tstd::string loadScreenPath = currentSkin[\"loadScreenPath\"].asString();\n\t\t\tsize_t nameStart = loadScreenPath.find(\"ASSETS/Characters/\") + strlen(\"ASSETS/Characters/\");\n\t\t\tstd::string champName = loadScreenPath.substr(nameStart, loadScreenPath.find('/', nameStart) - nameStart);\n\n\t\t\tstd::string name = currentSkin[\"name\"].asString();\n\n\t\t\tstd::pair<std::string, std::string> skin;\n\t\t\tif (currentSkin[\"isBase\"].asBool() == true)\n\t\t\t{\n\t\t\t\tchamps[champName].name = champName;\n\t\t\t\tstd::string champKey = id;\n\t\t\t\tif (champKey.size() >= 3 && champKey.substr(champKey.size() - 3) == \"000\") {\n\t\t\t\t\tchampKey.erase(champKey.size() - 3);\n\t\t\t\t}\n\n\t\t\t\tchamps[champName].key = std::stoi(champKey);\n\t\t\t\tskin.first = id;\n\t\t\t\tskin.second = \"default\";\n\t\t\t\tchamps[champName].skins.insert(champs[champName].skins.begin(), skin);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (currentSkin[\"questSkinInfo\"]) // K/DA ALL OUT Seraphine\n\t\t\t\t{\n\t\t\t\t\tfor (const Json::Value skinTiers = currentSkin[\"questSkinInfo\"][\"tiers\"]; const auto & skinTier : skinTiers)\n\t\t\t\t\t{\n\t\t\t\t\t\tskin.first = skinTier[\"id\"].asString();\n\t\t\t\t\t\tskin.second = skinTier[\"name\"].asString();\n\t\t\t\t\t\tchamps[champName].skins.emplace_back(skin);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tskin.first = id;\n\t\t\t\t\tskin.second = name;\n\t\t\t\t\tchamps[champName].skins.emplace_back(skin);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstd::vector<Champ> temp;\n\t\tfor (const auto& c : champs)\n\t\t{\n\t\t\ttemp.emplace_back(c.second);\n\t\t}\n\t\tchampSkins = temp;\n\t}\n\n\tstatic void TaskKillLeague()\n\t{\n\t\tfor (const std::vector<std::wstring> leagueProcs = {\n\t\t\t\t L\"RiotClientCrashHandler.exe\",\n\t\t\t\t L\"RiotClientServices.exe\",\n\t\t\t\t L\"RiotClientUx.exe\",\n\t\t\t\t L\"RiotClientUxRender.exe\",\n\t\t\t\t L\"Riot Client.exe\",\n\n\t\t\t\t L\"LeagueCrashHandler.exe\",\n\t\t\t\t L\"LeagueCrashHandler64.exe\",\n\t\t\t\t L\"LeagueClient.exe\",\n\t\t\t\t L\"LeagueClientUx.exe\",\n\t\t\t\t L\"LeagueClientUxRender.exe\"\n\t\t\t}; const auto & proc : leagueProcs)\n\t\t{\n\t\t\tTerminateProcessByName(proc);\n\t\t}\n\t}\n\n\tstatic std::string ChampIdToName(const int id)\n\t{\n\t\tif (!id)\n\t\t{\n\t\t\treturn \"None\";\n\t\t}\n\t\tif (champSkins.empty())\n\t\t{\n\t\t\treturn \"No data\"; // \"Champion data is still being fetched\";\n\t\t}\n\t\t{\n\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t{\n\t\t\t\tif (key == id)\n\t\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t// Terminate all league related processes,\n\t// remove read only and hidden property from files\n\t// and delete them\n\tstatic std::string ClearLogs()\n\t{\n\t\tstd::string result;\n\n\t\tTaskKillLeague();\n\n\t\tstd::this_thread::sleep_for(std::chrono::seconds(2));\n\n\t\tstd::error_code errorCode;\n\n\t\tconst auto leaguePath = std::filesystem::path(S.leaguePath);\n\n\t\tconst auto riotClientPath = std::filesystem::path(\n\t\t\tS.leaguePath.substr(0, S.leaguePath.find_last_of(\"/\\\\\", S.leaguePath.size() - 2))) / \"Riot Client\";\n\n\t\tchar* pLocal;\n\t\tsize_t localLen;\n\t\t_dupenv_s(&pLocal, &localLen, \"LOCALAPPDATA\");\n\t\tconst auto localAppData = std::filesystem::path(pLocal);\n\n\t\t_dupenv_s(&pLocal, &localLen, \"PROGRAMDATA\");\n\t\tconst auto programData = std::filesystem::path(pLocal);\n\n\t\tfor (const std::vector leagueFiles = {\n\t\t\t\t leaguePath / \"Logs\",\n\t\t\t\t leaguePath / \"Config\",\n\t\t\t\t leaguePath / \"debug.log\",\n\t\t\t\t leaguePath / \"Game\" / \"Logs\",\n\t\t\t\t riotClientPath / \"UX\" / \"natives_blob.bin\",\n\t\t\t\t riotClientPath / \"UX\" / \"snapshot_blob.bin\",\n\t\t\t\t riotClientPath / \"UX\" / \"v8_context_snapshot.bin\",\n\t\t\t\t riotClientPath / \"UX\" / \"icudtl.dat\",\n\t\t\t\t riotClientPath / \"UX\" / \"GPUCache\",\n\t\t\t\t localAppData / \"Riot Games\",\n\t\t\t\t programData / \"Riot Games\"\n\t\t\t}; const auto & file : leagueFiles)\n\t\t{\n\t\t\tif (exists(file))\n\t\t\t{\n\t\t\t\tSetFileAttributesA(file.string().c_str(),\n\t\t\t\t\tGetFileAttributesA(file.string().c_str()) & ~FILE_ATTRIBUTE_READONLY & ~FILE_ATTRIBUTE_HIDDEN);\n\t\t\t\tremove_all(file, errorCode);\n\t\t\t\tresult += file.string() + \" - \" + errorCode.message() + \"\\n\";\n\t\t\t}\n\t\t}\n\n\t\tint counter = 0;\n\t\tfor (const auto& file : std::filesystem::directory_iterator(std::filesystem::temp_directory_path()))\n\t\t{\n\t\t\tremove_all(file, errorCode);\n\t\t\tcounter++;\n\t\t}\n\t\tresult += \"Deleted \" + std::to_string(counter) + \" files in temp directory\\n\";\n\t\treturn result;\n\t}\n\n\t// returns true on success\n\tstatic bool TerminateProcessByName(const std::wstring& processName)\n\t{\n\t\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\t\tstatic auto pOpenProcess = (decltype(&OpenProcess))GetProcAddress(kernel32, \"OpenProcess\");\n\t\tstatic auto pCreateToolhelp32Snapshot = (decltype(&CreateToolhelp32Snapshot))GetProcAddress(kernel32, \"CreateToolhelp32Snapshot\");\n\t\tstatic auto pProcess32FirstW = (decltype(&Process32FirstW))GetProcAddress(kernel32, \"Process32FirstW\");\n\t\tstatic auto pProcess32NextW = (decltype(&Process32NextW))GetProcAddress(kernel32, \"Process32NextW\");\n\t\tstatic auto pTerminateProcess = (decltype(&TerminateProcess))GetProcAddress(kernel32, \"TerminateProcess\");\n\n\t\tconst HANDLE snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);\n\t\tbool result = false;\n\t\tif (snapshot != INVALID_HANDLE_VALUE)\n\t\t{\n\t\t\tPROCESSENTRY32W entry;\n\t\t\tentry.dwSize = sizeof(PROCESSENTRY32W);\n\t\t\tif (pProcess32FirstW(snapshot, &entry))\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tif (std::wstring(entry.szExeFile) == processName)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst HANDLE process = pOpenProcess(PROCESS_TERMINATE, false, entry.th32ProcessID);\n\t\t\t\t\t\tconst bool terminate = pTerminateProcess(process, 0);\n\t\t\t\t\t\tCloseHandle(process);\n\t\t\t\t\t\tresult = terminate;\n\t\t\t\t\t}\n\t\t\t\t} while (pProcess32NextW(snapshot, &entry));\n\t\t\t}\n\t\t}\n\t\tCloseHandle(snapshot);\n\t\treturn result;\n\t}\n};\n\ninline int FuzzySearch(const char* needle, void* data)\n{\n\tconst auto& items = *static_cast<std::vector<std::string>*>(data);\n\tfor (int i = 0; i < static_cast<int>(items.size()); i++)\n\t{\n\t\tconst auto haystack = items[i].c_str();\n\t\t// empty\n\t\tif (!needle[0])\n\t\t{\n\t\t\tif (!haystack[0])\n\t\t\t\treturn i;\n\t\t\tcontinue;\n\t\t}\n\t\t// exact match\n\t\tif (strstr(haystack, needle))\n\t\t\treturn i;\n\t\t// fuzzy match\n\t\tif (ISTRSTR(haystack, needle))\n\t\t\treturn i;\n\t}\n\treturn -1;\n}\n\nstatic bool itemsGetter(void* data, const int n, const char** out_str)\n{\n\tif (const auto& items = *static_cast<std::vector<std::string>*>(data); n >= 0 && n < static_cast<int>(items.size()))\n\t{\n\t\t*out_str = items[n].c_str();\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nnamespace ImGui\n{\n\t// Helper to display a little (?) mark which shows a tooltip when hovered.\n\t// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)\n\tstatic void HelpMarker(const char* desc)\n\t{\n\t\tTextDisabled(\"(?)\");\n\t\tif (IsItemHovered())\n\t\t{\n\t\t\tBeginTooltip();\n\t\t\tPushTextWrapPos(GetFontSize() * 35.0f);\n\t\t\tTextUnformatted(desc);\n\t\t\tPopTextWrapPos();\n\t\t\tEndTooltip();\n\t\t}\n\t}\n\n#pragma warning( push )\n#pragma warning( disable : 4505 ) //  warning C4505: 'ImGui::ArrowButtonDisabled': unreferenced function with internal linkage has been removed\n\tstatic void ArrowButtonDisabled(const char* id, const ImGuiDir dir) // UnusedFunction\n\t{\n\t\tPushStyleVar(ImGuiStyleVar_Alpha, GetStyle().Alpha * 0.5f);\n\t\tArrowButton(id, dir);\n\t\tPopStyleVar();\n\t}\n#pragma warning( pop )\n\n\tstatic void AddUnderLine(const ImColor& col)\n\t{\n\t\tImVec2 min = GetItemRectMin();\n\t\tconst ImVec2 max = GetItemRectMax();\n\t\tmin.y = max.y;\n\t\tGetWindowDrawList()->AddLine(min, max, col, 1.0f);\n\t}\n\n\tstatic void TextURL(const char* name, const char* url, uint8_t sameLineBefore = 1, uint8_t sameLineAfter = 1)\n\t{\n\t\tif (1 == sameLineBefore) { SameLine(0.0f, GetStyle().ItemInnerSpacing.x); }\n\t\tPushStyleColor(ImGuiCol_Text, GetStyle().Colors[ImGuiCol_ButtonHovered]);\n\t\tText(name); // PotentiallyInsecureFormatSecurity\n\t\tPopStyleColor();\n\t\tif (IsItemHovered())\n\t\t{\n\t\t\tif (IsMouseClicked(0))\n\t\t\t{\n\t\t\t\tUtils::OpenUrl(url, nullptr, SW_SHOWNORMAL);\n\t\t\t}\n\t\t\tAddUnderLine(GetStyle().Colors[ImGuiCol_ButtonHovered]);\n\t\t\tSetTooltip(\"  Open in browser\\n%s\", url);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddUnderLine(GetStyle().Colors[ImGuiCol_Button]);\n\t\t}\n\t\tif (1 == sameLineAfter) { SameLine(0.0f, GetStyle().ItemInnerSpacing.x); }\n\t}\n\n#pragma warning( push )\n#pragma warning( disable : 4996 )\n\tstruct ComboAutoSelectData\n\t{\n\t\tstd::vector<std::string> items;\n\t\tint index = -1;\n\t\tchar input[128] = {};\n\n\t\tComboAutoSelectData() = default;\n\n\t\texplicit ComboAutoSelectData(const std::vector<std::string>& hints, const int selected_index = -1)\n\t\t\t: items(hints)\n\t\t{\n\t\t\tif (selected_index > -1 && selected_index < static_cast<int>(items.size()))\n\t\t\t{\n\t\t\t\tstrncpy(input, items[selected_index].c_str(), sizeof(input) - 1);\n\t\t\t\tindex = selected_index;\n\t\t\t}\n\t\t}\n\t};\n\n\tinline bool ComboAutoSelectComplex(const char* label, char* input, const int inputlen, int* current_item,\n\t\tstd::vector<std::string> data, const int items_count, const ImGuiComboFlags flags)\n\t{\n\t\t// Always consume the SetNextWindowSizeConstraint() call in our early return paths\n\t\tconst ImGuiContext& g = *GImGui;\n\n\t\tImGuiWindow* window = GetCurrentWindow();\n\t\tif (window->SkipItems)\n\t\t\treturn false;\n\n\t\t// Call the getter to obtain the preview string which is a parameter to BeginCombo()\n\n\t\tconst ImGuiID popupId = window->GetID(label);\n\t\tbool popupIsAlreadyOpened = IsPopupOpen(popupId, 0); //ImGuiPopupFlags_AnyPopupLevel);\n\t\tconst char* sActiveidxValue1 = nullptr;\n\t\titemsGetter(&data, *current_item, &sActiveidxValue1);\n\t\tconst bool popupNeedsToBeOpened = (input[0] != 0) && (sActiveidxValue1 && strcmp(input, sActiveidxValue1));\n\t\tbool popupJustOpened = false;\n\n\t\tIM_ASSERT(\n\t\t\t(flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview));\n\t\t// Can't use both flags together\n\n\t\tconst ImGuiStyle& style = g.Style;\n\n\t\tconst float arrow_size = flags & ImGuiComboFlags_NoArrowButton ? 0.0f : GetFrameHeight();\n\t\tconst ImVec2 label_size = CalcTextSize(label, nullptr, true);\n\t\tconst float expected_w = CalcItemWidth();\n\t\tconst float w = flags & ImGuiComboFlags_NoPreview ? arrow_size : expected_w;\n\t\tconst ImRect frame_bb(window->DC.CursorPos,\n\t\t\tImVec2(window->DC.CursorPos.x + w, window->DC.CursorPos.y + label_size.y + style.FramePadding.y * 2.0f));\n\t\tconst ImRect total_bb(frame_bb.Min, ImVec2((label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f) + frame_bb.Max.x,\n\t\t\tframe_bb.Max.y));\n\t\tconst float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size);\n\t\tItemSize(total_bb, style.FramePadding.y);\n\t\tif (!ItemAdd(total_bb, popupId, &frame_bb))\n\t\t\treturn false;\n\n\t\tbool hovered, held;\n\t\tconst bool pressed = ButtonBehavior(frame_bb, popupId, &hovered, &held);\n\n\t\tif (!popupIsAlreadyOpened)\n\t\t{\n\t\t\tconst ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);\n\t\t\tRenderNavHighlight(frame_bb, popupId);\n\t\t\tif (!(flags & ImGuiComboFlags_NoPreview))\n\t\t\t\twindow->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding,\n\t\t\t\t\t(flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft);\n\t\t}\n\t\tif (!(flags & ImGuiComboFlags_NoArrowButton))\n\t\t{\n\t\t\tconst ImU32 bg_col = GetColorU32((popupIsAlreadyOpened || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\t\t\tconst ImU32 text_col = GetColorU32(ImGuiCol_Text);\n\t\t\twindow->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding,\n\t\t\t\t(w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight);\n\t\t\tif (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x)\n\t\t\t\tRenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down,\n\t\t\t\t\t1.0f);\n\t\t}\n\n\t\tif (!popupIsAlreadyOpened)\n\t\t{\n\t\t\tRenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);\n\t\t\tif (input != nullptr && !(flags & ImGuiComboFlags_NoPreview))\n\t\t\t{\n\t\t\t\tRenderTextClipped(\n\t\t\t\t\tImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y),\n\t\t\t\t\tImVec2(value_x2, frame_bb.Max.y),\n\t\t\t\t\tinput,\n\t\t\t\t\tnullptr,\n\t\t\t\t\tnullptr,\n\t\t\t\t\tImVec2(0.0f, 0.0f)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ((pressed || g.NavActivateId == popupId || popupNeedsToBeOpened) && !popupIsAlreadyOpened)\n\t\t\t{\n\t\t\t\tif (window->DC.NavLayerCurrent == 0)\n\t\t\t\t\twindow->NavLastIds[0] = popupId;\n\t\t\t\tOpenPopupEx(popupId);\n\t\t\t\tpopupIsAlreadyOpened = true;\n\t\t\t\tpopupJustOpened = true;\n\t\t\t}\n\t\t}\n\n\t\tif (label_size.x > 0)\n\t\t{\n\t\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);\n\t\t}\n\n\t\tif (!popupIsAlreadyOpened)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tconst float totalWMinusArrow = w - arrow_size;\n\t\tstruct ImGuiSizeCallbackWrapper\n\t\t{\n\t\t\tstatic void sizeCallback(ImGuiSizeCallbackData* data)\n\t\t\t{\n\t\t\t\tconst float* totalWMinusArrow = static_cast<float*>(data->UserData);\n\t\t\t\tdata->DesiredSize = ImVec2(*totalWMinusArrow, 200.f);\n\t\t\t}\n\t\t};\n\t\tSetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(totalWMinusArrow, 150.f), ImGuiSizeCallbackWrapper::sizeCallback, (void*)&totalWMinusArrow);\n\n\t\tchar name[16];\n\t\tImFormatString(name, IM_ARRAYSIZE(name), \"##Combo_%02d\", g.BeginPopupStack.Size); // Recycle windows based on depth\n\n\t\t// Peek into expected window size so we can position it\n\t\tif (ImGuiWindow* popup_window = FindWindowByName(name))\n\t\t{\n\t\t\tif (popup_window->WasActive)\n\t\t\t{\n\t\t\t\tconst ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window);\n\t\t\t\tif (flags & ImGuiComboFlags_PopupAlignLeft)\n\t\t\t\t\tpopup_window->AutoPosLastDirection = ImGuiDir_Left;\n\t\t\t\tconst ImRect r_outer = GetPopupAllowedExtentRect(popup_window);\n\t\t\t\tImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb,\n\t\t\t\t\tImGuiPopupPositionPolicy_ComboBox);\n\n\t\t\t\tpos.y -= label_size.y + style.FramePadding.y * 2.0f;\n\n\t\t\t\tSetNextWindowPos(pos);\n\t\t\t}\n\t\t}\n\n\t\t// Horizontally align ourselves with the framed text\n\t\tconstexpr ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar |\n\t\t\tImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;\n\t\t//    PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y));\n\t\tconst bool ret = Begin(name, nullptr, window_flags);\n\n\t\tPushItemWidth(GetWindowWidth());\n\t\tSetCursorPos(ImVec2(0.f, window->DC.CurrLineTextBaseOffset));\n\t\tif (popupJustOpened)\n\t\t{\n\t\t\tSetKeyboardFocusHere(0);\n\t\t}\n\n\t\tconst bool done = InputTextEx(\"##inputText\", nullptr, input, inputlen, ImVec2(0, 0),\n\t\t\tImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue, nullptr, nullptr);\n\t\tPopItemWidth();\n\n\t\tif (!ret)\n\t\t{\n\t\t\tEndChild();\n\t\t\tPopItemWidth();\n\t\t\tEndPopup();\n\t\t\tIM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above\n\t\t\treturn false;\n\t\t}\n\n\t\tconstexpr ImGuiWindowFlags window_flags2 = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus;\n\t\t//0; //ImGuiWindowFlags_HorizontalScrollbar\n\t\tBeginChild(\"ChildL\", ImVec2(GetContentRegionAvail().x, GetContentRegionAvail().y), false, window_flags2);\n\n\t\tbool selectionChanged = false;\n\t\tif (input[0] != '\\0')\n\t\t{\n\t\t\tconst int new_idx = FuzzySearch(input, &data);\n\t\t\tconst int idx = new_idx >= 0 ? new_idx : *current_item;\n\t\t\tselectionChanged = *current_item != idx;\n\t\t\t*current_item = idx;\n\t\t}\n\n\t\tbool arrowScroll = false;\n\t\t//int arrowScrollIdx = *current_item;\n\n\t\tif (IsKeyPressed(GetKeyIndex(ImGuiKey_UpArrow)))\n\t\t{\n\t\t\tif (*current_item > 0)\n\t\t\t{\n\t\t\t\t*current_item -= 1;\n\t\t\t\tarrowScroll = true;\n\t\t\t\tSetWindowFocus();\n\t\t\t}\n\t\t}\n\t\tif (IsKeyPressed(GetKeyIndex(ImGuiKey_DownArrow)))\n\t\t{\n\t\t\tif (*current_item >= -1 && *current_item < items_count - 1)\n\t\t\t{\n\t\t\t\t*current_item += 1;\n\t\t\t\tarrowScroll = true;\n\t\t\t\tSetWindowFocus();\n\t\t\t}\n\t\t}\n\n\t\t// select the first match\n\t\tif (IsKeyPressed(GetKeyIndex(ImGuiKey_Enter)))\n\t\t{\n\t\t\tarrowScroll = true;\n\t\t\t*current_item = FuzzySearch(input, &data);\n\t\t\tif (*current_item < 0)\n\t\t\t\t*input = 0;\n\t\t\tCloseCurrentPopup();\n\t\t}\n\n\t\tif (IsKeyPressed(GetKeyIndex(ImGuiKey_Backspace)))\n\t\t{\n\t\t\t*current_item = FuzzySearch(input, &data);\n\t\t\tselectionChanged = true;\n\t\t}\n\n\t\tif (done && !arrowScroll)\n\t\t{\n\t\t\tCloseCurrentPopup();\n\t\t}\n\n\t\tbool done2 = false;\n\n\t\tfor (int n = 0; n < items_count; n++)\n\t\t{\n\t\t\tconst bool is_selected = n == *current_item;\n\t\t\tif (is_selected && (IsWindowAppearing() || selectionChanged))\n\t\t\t{\n\t\t\t\tSetScrollHereY();\n\t\t\t}\n\n\t\t\tif (is_selected && arrowScroll)\n\t\t\t{\n\t\t\t\tSetScrollHereY();\n\t\t\t}\n\n\t\t\tconst char* select_value = nullptr;\n\t\t\titemsGetter(&data, n, &select_value);\n\n\t\t\t// allow empty item\n\t\t\tchar item_id[128];\n\t\t\tImFormatString(item_id, sizeof(item_id), \"%s##item_%02d\", select_value, n);\n\t\t\tif (Selectable(item_id, is_selected))\n\t\t\t{\n\t\t\t\tselectionChanged = *current_item != n;\n\t\t\t\t*current_item = n;\n\t\t\t\tstrncpy(input, select_value, inputlen);\n\t\t\t\tCloseCurrentPopup();\n\t\t\t\tdone2 = true;\n\t\t\t}\n\t\t}\n\n\t\tif (arrowScroll && *current_item > -1)\n\t\t{\n\t\t\tconst char* sActiveidxValue2 = nullptr;\n\t\t\titemsGetter(&data, *current_item, &sActiveidxValue2);\n\t\t\tstrncpy(input, sActiveidxValue2, inputlen);\n\t\t\tImGuiWindow* wnd = FindWindowByName(name);\n\t\t\tconst ImGuiID id = wnd->GetID(\"##inputText\");\n\t\t\tImGuiInputTextState* state = GetInputTextState(id);\n\n\t\t\tconst char* buf_end = nullptr;\n\t\t\tstate->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, input, nullptr, &buf_end);\n\t\t\tstate->CurLenA = static_cast<int>(buf_end - input);\n\t\t\tstate->CursorClamp();\n\t\t}\n\n\t\tEndChild();\n\t\tEndPopup();\n\n\t\tconst char* sActiveidxValue3 = nullptr;\n\t\titemsGetter(&data, *current_item, &sActiveidxValue3);\n\t\tconst bool ret1 = (selectionChanged && (sActiveidxValue3 && !strcmp(sActiveidxValue3, input)));\n\n\t\tconst bool widgetRet = done || done2 || ret1;\n\n\t\treturn widgetRet;\n\t}\n#pragma warning( pop )\n\n\tstatic bool ComboAutoSelect(const char* label, ComboAutoSelectData& data, const ImGuiComboFlags flags = 0)\n\t{\n\t\treturn ComboAutoSelectComplex(label, data.input, sizeof(data.input) - 1, &data.index, data.items, static_cast<int>(data.items.size()), flags);\n\t}\n}\n"
  },
  {
    "path": "KBotExt/MiscTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"LCU.h\"\n#include \"Misc.h\"\n#include \"Config.h\"\n\nclass MiscTab\n{\npublic:\n\tstatic std::string LevenshteinDistance(std::vector<std::string> vec, std::string str2)\n\t{\n\t\tsize_t max = 999;\n\t\tstd::string bestMatch;\n\n\t\tfor (const std::string& str1 : vec)\n\t\t{\n\t\t\tconst size_t str1Len = str1.length();\n\t\t\tconst size_t str2Len = str2.length();\n\t\t\tsize_t d[50 + 1][50 + 1];\n\n\t\t\tsize_t i;\n\t\t\tsize_t j;\n\t\t\tsize_t cost;\n\n\t\t\tfor (i = 0; i <= str1Len; i++)\n\t\t\t{\n\t\t\t\td[i][0] = i;\n\t\t\t}\n\t\t\tfor (j = 0; j <= str2Len; j++)\n\t\t\t{\n\t\t\t\td[0][j] = j;\n\t\t\t}\n\t\t\tfor (i = 1; i <= str1Len; i++)\n\t\t\t{\n\t\t\t\tfor (j = 1; j <= str2Len; j++)\n\t\t\t\t{\n\t\t\t\t\tif (str1[i - 1] == str2[j - 1])\n\t\t\t\t\t{\n\t\t\t\t\t\tcost = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcost = 1;\n\t\t\t\t\t}\n\t\t\t\t\td[i][j] = (std::min)(\n\t\t\t\t\t\td[i - 1][j] + 1, // delete\n\t\t\t\t\t\t(std::min)(d[i][j - 1] + 1, // insert\n\t\t\t\t\t\t\td[i - 1][j - 1] + cost) // substitution\n\t\t\t\t\t\t);\n\t\t\t\t\tif (i > 1 &&\n\t\t\t\t\t\tj > 1 &&\n\t\t\t\t\t\tstr1[i - 1] == str2[j - 2] &&\n\t\t\t\t\t\tstr1[i - 2] == str2[j - 1]\n\t\t\t\t\t\t)\n\t\t\t\t\t{\n\t\t\t\t\t\td[i][j] = (std::min)(\n\t\t\t\t\t\t\td[i][j],\n\t\t\t\t\t\t\td[i - 2][j - 2] + cost // transposition\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (d[str1Len][str2Len] <= max)\n\t\t\t{\n\t\t\t\tmax = d[str1Len][str2Len];\n\t\t\t\tbestMatch = str1;\n\t\t\t}\n\t\t}\n\t\treturn bestMatch;\n\t}\n\n\tstatic void Render()\n\t{\n\t\tstatic bool onOpen = true;\n\t\tif (ImGui::BeginTabItem(\"Misc\"))\n\t\t{\n\t\t\tstatic std::string result;\n\n\t\t\t// Get processes every 5 seconds\n\t\t\tstatic auto timeBefore = std::chrono::high_resolution_clock::now();\n\t\t\tstd::chrono::duration<float, std::milli> timeDuration = std::chrono::high_resolution_clock::now() - timeBefore;\n\t\t\tif (timeDuration.count() > 5000 || onOpen)\n\t\t\t{\n\t\t\t\ttimeBefore = std::chrono::high_resolution_clock::now();\n\t\t\t\tLCU::GetLeagueProcesses();\n\t\t\t}\n\n\t\t\tImGui::Text(\"Selected process: \");\n\t\t\tImGui::SameLine();\n\n\t\t\tstd::string comboProcesses;\n\t\t\tif (LCU::IsProcessGood())\n\t\t\t{\n\t\t\t\tcomboProcesses = std::to_string(LCU::leagueProcesses[LCU::indexLeagueProcesses].first)\n\t\t\t\t\t+ \" : \" + LCU::leagueProcesses[LCU::indexLeagueProcesses].second;\n\t\t\t}\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 3));\n\t\t\tif (ImGui::BeginCombo(\"##comboProcesses\", comboProcesses.c_str(), 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < LCU::leagueProcesses.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (LCU::indexLeagueProcesses == n);\n\t\t\t\t\tif (ImGui::Selectable((std::to_string(LCU::leagueProcesses[n].first) + \" : \" + LCU::leagueProcesses[n].second).c_str(),\n\t\t\t\t\t\tis_selected))\n\t\t\t\t\t{\n\t\t\t\t\t\tLCU::indexLeagueProcesses = n;\n\t\t\t\t\t\tLCU::SetLeagueClientInfo();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Launch another client\"))\n\t\t\t{\n\t\t\t\tif (!std::filesystem::exists(S.leaguePath))\n\t\t\t\t{\n\t\t\t\t\tresult = \"Invalid path, change it in Settings tab\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tUtils::OpenUrl(std::format(\"{}LeagueClient.exe\", S.leaguePath).c_str(), \"--allow-multiple-clients\", SW_SHOWNORMAL);\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Restart UX\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/riotclient/kill-and-restart-ux\", \"\");\n\t\t\t\tif (result.find(\"failed\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tif (LCU::SetLeagueClientInfo())\n\t\t\t\t\t\tresult = \"Rehooked to new league client\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Launch legacy client\"))\n\t\t\t{\n\t\t\t\tif (!std::filesystem::exists(S.leaguePath))\n\t\t\t\t{\n\t\t\t\t\tresult = \"Invalid path, change it in Settings tab\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tMisc::LaunchLegacyClient();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Close client\"))\n\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/process-control/v1/process/quit\", \"\");\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Accept all friend requests\"))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Accepting friend requests\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tstd::string getFriends = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friend-requests\");\n\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (!reader->parse(getFriends.c_str(), getFriends.c_str() + static_cast<int>(getFriends.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = \"Failed to parse JSON\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::string req = \"https://127.0.0.1/lol-chat/v1/friend-requests/\" + i[\"pid\"].asString();\n\t\t\t\t\t\t\t\tLCU::Request(\"PUT\", req, R\"({\"direction\":\"both\"})\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult = \"Accepted \" + std::to_string(root.size()) + \" friend requests\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Delete all friend requests\"))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Deleting friend requests\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tstd::string getFriends = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friend-requests\");\n\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (!reader->parse(getFriends.c_str(), getFriends.c_str() + static_cast<int>(getFriends.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = \"Failed to parse JSON\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::string req = \"https://127.0.0.1/lol-chat/v1/friend-requests/\" + i[\"pid\"].asString();\n\t\t\t\t\t\t\t\tLCU::Request(\"DELETE\", req, \"\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult = \"Deleted \" + std::to_string(root.size()) + \" friend requests\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tstatic std::vector<std::pair<std::string, int>> items = { {\"**Default\", 0} };\n\t\t\tstatic size_t item_current_idx = 0; // Here we store our selection data as an index.\n\t\t\tauto combo_label = items[item_current_idx].first.c_str();\n\n\t\t\tif (ImGui::Button(\"Remove all friends\"))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Removing friends\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tstd::string getFriends = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friends\");\n\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value root;\n\t\t\t\t\tif (!reader->parse(getFriends.c_str(), getFriends.c_str() + static_cast<int>(getFriends.length()), &root, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = \"Failed to parse JSON\";\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint iDeleted = 0;\n\t\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (i[\"groupId\"].asInt() == items[item_current_idx].second)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstd::string req = \"https://127.0.0.1/lol-chat/v1/friends/\" + i[\"pid\"].asString();\n\t\t\t\t\t\t\t\t\tLCU::Request(\"DELETE\", req, \"\");\n\t\t\t\t\t\t\t\t\tiDeleted++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult = \"Deleted \" + std::to_string(iDeleted) + \" friends\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\" From folder: \");\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(ImGui::CalcTextSize(std::string(20, 'W').c_str(), nullptr, true).x);\n\t\t\tif (ImGui::BeginCombo(\"##comboGroups\", combo_label, 0))\n\t\t\t{\n\t\t\t\tstd::string getGroups = LCU::Request(\"GET\", \"https://127.0.0.1/lol-chat/v1/friend-groups\");\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(getGroups.c_str(), getGroups.c_str() + static_cast<int>(getGroups.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\titems.clear();\n\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::pair temp = { i[\"name\"].asString(), i[\"id\"].asInt() };\n\t\t\t\t\t\t\titems.emplace_back(temp);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstd::ranges::sort(items, [](std::pair<std::string, int> a, std::pair<std::string, int> b) { return a.second < b.second; });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (size_t n = 0; n < items.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (item_current_idx == n);\n\t\t\t\t\tif (ImGui::Selectable(items[n].first.c_str(), is_selected))\n\t\t\t\t\t\titem_current_idx = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\t//if (ImGui::Button(\"Skip tutorial\"))\n\t\t\t//{\n\t\t\t//\thttp->Request(\"POST\", \"https://127.0.0.1/telemetry/v1/events/new_player_experience\", R\"({\"eventName\":\"hide_screen\",\"plugin\":\"rcp-fe-lol-new-player-experience\",\"screenName\":\"npe_tutorial_modules\"})\", auth->leagueHeader, \"\", \"\", auth->leaguePort);\n\t\t\t//\thttp->Request(\"PUT\", \"https://127.0.0.1/lol-npe-tutorial-path/v1/settings\", R\"({\"hasSeenTutorialPath\":true,\"hasSkippedTutorialPath\":true,\"shouldSeeNewPlayerExperience\":true})\", auth->leagueHeader, \"\", \"\", auth->leaguePort);\n\t\t\t//\tDELETE https://127.0.0.1:63027/lol-statstones/v1/vignette-notifications HTTP/1.1\n\t\t\t//\t// ?\n\t\t\t//}\n\n\t\t\t// Patched :(\n\t\t\t//if (ImGui::Button(\"Free Tristana + Riot Girl skin\"))\n\t\t\t//\tresult = http->Request(\"POST\", \"https://127.0.0.1/lol-login/v1/session/invoke?destination=inventoryService&method=giftFacebookFan&args=[]\", \"\", auth->leagueHeader, \"\", \"\", auth->leaguePort);\n\n\t\t\t//ImGui::SameLine();\n\t\t\t//Misc::HelpMarker(\"Relog after pressing the button\");\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic int minimapScale = 100;\n\t\t\tImGui::Text(\"In-game minimap scale: \");\n\t\t\tImGui::SameLine();\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 3));\n\t\t\tImGui::SliderInt(\"##sliderMinimapScale\", &minimapScale, 0, 350, \"%d\");\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Submit##submitMinimapScale\"))\n\t\t\t{\n\t\t\t\tresult = LCU::Request(\"PATCH\", \"https://127.0.0.1/lol-game-settings/v1/game-settings\",\n\t\t\t\t\tstd::format(R\"({{\"HUD\":{{\"MinimapScale\":{:.2f}}}}})\", minimapScale / 33.33f));\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic std::vector<std::pair<std::string, std::string>> itemsDisenchant = {\n\t\t\t\t{\"Champion shards\", \"CHAMPION_RENTAL\"}, {\"Champion pernaments\", \"CHAMPION\"},\n\t\t\t\t{\"Skin shards\", \"CHAMPION_SKIN_RENTAL\"}, {\"Skin pernaments\", \"CHAMPION_SKIN\"},\n\t\t\t\t{\"Eternals\", \"STATSTONE_SHARD\"}, {\"Ward shards\", \"WARD_SKIN_RENTAL\"}, {\"Ward pernaments\", \"WARD_SKIN\",},\n\t\t\t\t{\"Emotes\", \"EMOTE\"}, {\"Icons\", \"SUMMONER_ICON\"}, {\"Companions\", \"COMPANION\"}\n\t\t\t};\n\t\t\tstatic size_t itemIndexDisenchant = 0;\n\t\t\tconst char* comboDisenchant = itemsDisenchant[itemIndexDisenchant].first.c_str();\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Disenchant all: \"))\n\t\t\t{\n\t\t\t\tJson::Value root;\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tstd::string getLoot = LCU::Request(\"GET\", \"https://127.0.0.1/lol-loot/v1/player-loot-map\", \"\");\n\n\t\t\t\tif (reader->parse(getLoot.c_str(), getLoot.c_str() + static_cast<int>(getLoot.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Disenchanting loot\", MB_OKCANCEL) == IDOK)\n\t\t\t\t\t{\n\t\t\t\t\t\tint i = 0;\n\n\t\t\t\t\t\tfor (const std::string& name : root.getMemberNames())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (std::regex regexStr(\"^\" + itemsDisenchant[itemIndexDisenchant].second + \"_[\\\\d]+\"); std::regex_match(name, regexStr))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstd::string disenchantCase = itemsDisenchant[itemIndexDisenchant].second == \"STATSTONE_SHARD\"\n\t\t\t\t\t\t\t\t\t? \"DISENCHANT\"\n\t\t\t\t\t\t\t\t\t: \"disenchant\";\n\t\t\t\t\t\t\t\tstd::string disenchantName = root[name][\"type\"].asString();\n\n\t\t\t\t\t\t\t\tstd::string disenchantUrl = std::format(\"https://127.0.0.1/lol-loot/v1/recipes/{0}_{1}/craft?repeat=1\",\n\t\t\t\t\t\t\t\t\tdisenchantName, disenchantCase);\n\t\t\t\t\t\t\t\tstd::string disenchantBody = std::format(R\"([\"{}\"])\", name);\n\t\t\t\t\t\t\t\tLCU::Request(\"POST\", disenchantUrl, disenchantBody);\n\t\t\t\t\t\t\t\ti++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult = std::format(\"Disenchanted {0} {1}\", std::to_string(i), itemsDisenchant[itemIndexDisenchant].first);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tresult = \"Loot not found\";\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 3.5));\n\t\t\tif (ImGui::BeginCombo(\"##comboDisenchant\", comboDisenchant, 0))\n\t\t\t{\n\t\t\t\tfor (size_t n = 0; n < itemsDisenchant.size(); n++)\n\t\t\t\t{\n\t\t\t\t\tconst bool is_selected = (itemIndexDisenchant == n);\n\t\t\t\t\tif (ImGui::Selectable(itemsDisenchant[n].first.c_str(), is_selected))\n\t\t\t\t\t\titemIndexDisenchant = n;\n\n\t\t\t\t\tif (is_selected)\n\t\t\t\t\t\tImGui::SetItemDefaultFocus();\n\t\t\t\t}\n\t\t\t\tImGui::EndCombo();\n\t\t\t}\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Refund last purchase\"))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Refunding last purchase\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\t\tJSONCPP_STRING err;\n\t\t\t\t\tJson::Value rootPurchaseHistory;\n\n\t\t\t\t\tcpr::Header storeHeader = Utils::StringToHeader(LCU::GetStoreHeader());\n\n\t\t\t\t\tstd::string storeUrl = LCU::Request(\"GET\", \"/lol-store/v1/getStoreUrl\");\n\t\t\t\t\tstd::erase(storeUrl, '\"');\n\n\t\t\t\t\tstd::string purchaseHistory = cpr::Get(cpr::Url{ storeUrl + \"/storefront/v3/history/purchase\" }, cpr::Header{ storeHeader }).text;\n\t\t\t\t\tif (reader->parse(purchaseHistory.c_str(), purchaseHistory.c_str() + static_cast<int>(purchaseHistory.length()),\n\t\t\t\t\t\t&rootPurchaseHistory, &err))\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string accountId = rootPurchaseHistory[\"player\"][\"accountId\"].asString();\n\t\t\t\t\t\tstd::string transactionId = rootPurchaseHistory[\"transactions\"][0][\"transactionId\"].asString();\n\t\t\t\t\t\tresult = cpr::Post(cpr::Url{ storeUrl + \"/storefront/v3/refund\" }, cpr::Header{ storeHeader },\n\t\t\t\t\t\t\tcpr::Body{\n\t\t\t\t\t\t\t\t\"{\\\"accountId\\\":\" + accountId + R\"(,\"transactionId\":\")\" + transactionId +\n\t\t\t\t\t\t\t\tR\"(\",\"inventoryType\":\"CHAMPION\",\"language\":\"en_US\"})\"\n\t\t\t\t\t\t\t}).text;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = purchaseHistory;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Can refund anything, even loot\");\n\n\t\t\tImGui::Columns(1);\n\n\t\t\t// Getting closest champion name with Levenshtein distance algorithm and getting it's id\n\t\t\tImGui::Text(\"Champion name to ID\");\n\t\t\tstatic std::vector<std::string> champNames;\n\t\t\tif (!champSkins.empty() && champNames.empty())\n\t\t\t{\n\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t{\n\t\t\t\t\tchampNames.emplace_back(name);\n\t\t\t\t\t//std::cout << \"('\" << champ.name << \"', \" << champ.key << \"), \" << std::endl;\n\t\t\t\t\tstd::cout << name << std::endl;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic char bufChampionName[50];\n\t\t\tstatic size_t lastSize = 0;\n\t\t\tstatic std::string closestChampion;\n\t\t\tstatic std::string closestId;\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 3));\n\t\t\tImGui::InputText(\"##inputChampionName\", bufChampionName, IM_ARRAYSIZE(bufChampionName));\n\t\t\tif (strlen(bufChampionName) < 1)\n\t\t\t{\n\t\t\t\tclosestChampion = \"\";\n\t\t\t\tclosestId = \"\";\n\t\t\t\tlastSize = 0;\n\t\t\t}\n\t\t\telse if (lastSize != strlen(bufChampionName))\n\t\t\t{\n\t\t\t\tlastSize = strlen(bufChampionName);\n\t\t\t\tclosestChampion = LevenshteinDistance(champNames, bufChampionName);\n\n\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t{\n\t\t\t\t\tif (closestChampion == name)\n\t\t\t\t\t{\n\t\t\t\t\t\tclosestId = std::to_string(key);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::TextWrapped(\"%s ID: %s\", closestChampion.c_str(), closestId.c_str());\n\n\t\t\t/*if (ImGui::Button(\"Check email of the account\"))\n\t\t\t\tresult = LCU::Request(\"GET\", \"https://127.0.0.1/lol-email-verification/v1/email\");*/\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Text(\"Change your Riot ID:\");\n\t\t\tstatic char bufGameName[50];\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 4));\n\t\t\tImGui::InputText(\"##inputGameName\", bufGameName, IM_ARRAYSIZE(bufGameName));\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\"#\");\n\t\t\tImGui::SameLine();\n\t\t\tstatic char bufTagLine[50];\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 5));\n\t\t\tImGui::InputText(\"##inputTagLine\", bufTagLine, IM_ARRAYSIZE(bufTagLine));\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Change##buttonRiotID\"))\n\t\t\t{\n\t\t\t\tstd::string newRiotId = std::string(bufGameName) + \"#\" + std::string(bufTagLine);\n\t\t\t\tif (MessageBoxA(nullptr, std::string(\"Your new Riot ID will be: \" + newRiotId).c_str(), \"Are you sure?\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tresult = LCU::Request(\"POST\", \"https://127.0.0.1/lol-summoner/v1/save-alias\",\n\t\t\t\t\t\t\"{\\\"gameName\\\": \\\"\" + std::string(bufGameName) + \"\\\", \\\"tagLine\\\": \\\"\" + std::string(bufTagLine) + \"\\\"}\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Get email\"))\n\t\t\t{\n\t\t\t\tMessageBoxA(nullptr, \"Login\\nClick on 'My Tickets'\\nCtrl+Shift+I\\nCtrl+F and search for \\\"email\\\"\", \"Info\", MB_OK | MB_SETFOREGROUND);\n\n\t\t\t\tUtils::OpenUrl(L\"https://auth.riotgames.com/authorize?redirect_uri=https://login.playersupport.riotgames.com/login_callback&client_id=player-support-zendesk&ui_locales=en-us%20en-us&response_type=code&scope=openid%20email\"\n\t\t\t\t\t, nullptr, SW_SHOW);\n\t\t\t}\n\n\t\t\t//\t\t\tif (ImGui::Button(\"Tournament of Souls - unlock all\"))\n\t\t\t//\t\t\t{\n\t\t\t//\t\t\t\tLCU::Request(\"POST\", \"/lol-marketing-preferences/v1/partition/sfm2023\", R\"({\n\t\t\t//\t\"SmallConspiracyFan\" : \"True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True\",\n\t\t\t//\t\"SmallGwenPykeFan\" : \"True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True\",\n\t\t\t//\t\"SmallJhinFan\" : \"True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True\",\n\t\t\t//\t\"SmallSettFans\" : \"True,True,True,True,True,True,True,True,True,True,True,True,True,True,True\",\n\t\t\t//\t\"SmallShaco\" : \"True,True\",\n\t\t\t//\t\"hasNewAbility\" : \"False\",\n\t\t\t//\t\"hasNewFanLine\" : \"False\",\n\t\t\t//\t\"hasPlayedTutorial\" : \"True\",\n\t\t\t//\t\"hasSeenCelebration_Story\" : \"True\",\n\t\t\t//\t\"hasSeenLoadoutTutorial\" : \"True\",\n\t\t\t//\t\"hasSeenMapTutorial\" : \"True\",\n\t\t\t//\t\"loadout_active_e\" : \"2\",\n\t\t\t//\t\"loadout_active_q\" : \"1\",\n\t\t\t//\t\"loadout_active_r\" : \"2\",\n\t\t\t//\t\"loadout_active_w\" : \"2\",\n\t\t\t//\t\"numNodesUnlocked\" : \"20\",\n\t\t\t//\t\"progress\" : \"20\"\n\t\t\t//})\");\n\t\t\t//\n\t\t\t//\t\t\t\tJson::Value root;\n\t\t\t//\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t//\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t//\t\t\t\tJSONCPP_STRING err;\n\t\t\t//\t\t\t\tstd::string getGrants = LCU::Request(\"GET\", \"/lol-rewards/v1/grants\");\n\t\t\t//\n\t\t\t//\t\t\t\tif (reader->parse(getGrants.c_str(), getGrants.c_str() + static_cast<int>(getGrants.length()), &root, &err))\n\t\t\t//\t\t\t\t{\n\t\t\t//\t\t\t\t\tif (root.isArray())\n\t\t\t//\t\t\t\t\t{\n\t\t\t//\t\t\t\t\t\tfor (auto grant : root)\n\t\t\t//\t\t\t\t\t\t{\n\t\t\t//\t\t\t\t\t\t\tfor (Json::Value& reward : grant[\"rewardGroup\"][\"rewards\"])\n\t\t\t//\t\t\t\t\t\t\t{\n\t\t\t//\t\t\t\t\t\t\t\tJson::Value body;\n\t\t\t//\t\t\t\t\t\t\t\tbody[\"rewardGroupId\"] = grant[\"info\"][\"rewardGroupId\"].asString();\n\t\t\t//\t\t\t\t\t\t\t\tbody[\"selections\"] = {};\n\t\t\t//\t\t\t\t\t\t\t\tbody[\"selections\"].append(reward[\"id\"].asString());\n\t\t\t//\n\t\t\t//\t\t\t\t\t\t\t\tresult += LCU::Request(\"POST\", std::format(\"/lol-rewards/v1/grants/{}/select\", grant[\"info\"][\"id\"].asString()),\n\t\t\t//\t\t\t\t\t\t\t\t\tbody.toStyledString());\n\t\t\t//\t\t\t\t\t\t\t}\n\t\t\t//\t\t\t\t\t\t}\n\t\t\t//\t\t\t\t\t}\n\t\t\t//\t\t\t\t}\n\t\t\t//\t\t\t}\n\t\t\t//\n\t\t\t//\t\t\tImGui::SameLine();\n\t\t\t//\t\t\tImGui::HelpMarker(\"You need reputation for this to work\");\n\n\t\t\tstatic Json::StreamWriterBuilder wBuilder;\n\t\t\tstatic std::string sResultJson;\n\t\t\tstatic char* cResultJson;\n\n\t\t\tif (!result.empty())\n\t\t\t{\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (!reader->parse(result.c_str(), result.c_str() + static_cast<int>(result.length()), &root, &err))\n\t\t\t\t\tsResultJson = result;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsResultJson = Json::writeString(wBuilder, root);\n\t\t\t\t}\n\t\t\t\tresult = \"\";\n\t\t\t}\n\n\t\t\tif (!sResultJson.empty())\n\t\t\t{\n\t\t\t\tcResultJson = sResultJson.data();\n\t\t\t\tImGui::InputTextMultiline(\"##miscResult\", cResultJson, sResultJson.size() + 1, ImVec2(600, 185));\n\t\t\t}\n\n\t\t\tif (onOpen)\n\t\t\t\tonOpen = false;\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tonOpen = true;\n\t\t}\n\t}\n};\n"
  },
  {
    "path": "KBotExt/ProfileTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"LCU.h\"\n\nclass ProfileTab\n{\npublic:\n\tstatic void Render()\n\t{\n\t\tif (ImGui::BeginTabItem(\"Profile\"))\n\t\t{\n\t\t\tstatic char statusText[1024 * 16];\n\t\t\tImGui::Text(\"Status:\");\n\t\t\tconst ImVec2 label_size = ImGui::CalcTextSize(\"W\", nullptr, true);\n\n\t\t\tImGui::InputTextMultiline(\"##inputStatus\", statusText, IM_ARRAYSIZE(statusText), ImVec2(S.Window.width - 230.f,\n\t\t\t\t(label_size.y + ImGui::GetStyle().FramePadding.y) * 6.f), ImGuiInputTextFlags_AllowTabInput);\n\t\t\tif (ImGui::Button(\"Submit status\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"statusMessage\":\")\" + std::string(statusText) + \"\\\"}\";\n\n\t\t\t\tsize_t nPos = 0;\n\t\t\t\twhile (nPos != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tnPos = body.find('\\n', nPos);\n\t\t\t\t\tif (nPos != std::string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tbody.erase(body.begin() + nPos);\n\t\t\t\t\t\tbody.insert(nPos, \"\\\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstd::string result = LCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\", body);\n\t\t\t\tif (result.find(\"errorCode\") != std::string::npos)\n\t\t\t\t\tMessageBoxA(nullptr, result.c_str(), nullptr, 0);\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tstatic int availability = 0;\n\t\t\tstatic int lastAvailability = 0;\n\t\t\tImGui::RadioButton(\"Online\", &availability, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Mobile\", &availability, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Away\", &availability, 2);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Offline\", &availability, 3);\n\n\t\t\tif (availability != lastAvailability)\n\t\t\t{\n\t\t\t\tlastAvailability = availability;\n\t\t\t\tstd::string body = R\"({\"availability\":\")\";\n\t\t\t\tswitch (availability)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tbody += \"online\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tbody += \"mobile\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbody += \"away\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbody += \"offline\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\t\t\t\tbody += \"\\\"}\";\n\t\t\t\tLCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\", body);\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\"\\t   \");\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Disconnect from chat\"))\n\t\t\t{\n\t\t\t\tLCU::SetCurrentClientRiotInfo();\n\t\t\t\tcpr::Post(cpr::Url{ std::format(\"https://127.0.0.1:{}/chat/v1/suspend\", LCU::riot.port) },\n\t\t\t\t\tcpr::Body{ \"{\\\"config\\\":\\\"disable\\\"}\" },\n\t\t\t\t\tcpr::Header{ Utils::StringToHeader(LCU::riot.header) }, cpr::VerifySsl{ false });\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Reconnect to chat\"))\n\t\t\t{\n\t\t\t\tLCU::SetCurrentClientRiotInfo();\n\t\t\t\tcpr::Post(cpr::Url{ std::format(\"https://127.0.0.1:{}/chat/v1/resume\", LCU::riot.port) },\n\t\t\t\t\tcpr::Header{ Utils::StringToHeader(LCU::riot.header) }, cpr::VerifySsl{ false });\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Text(\"Rank:\");\n\t\t\tstatic int rank = 0;\n\t\t\tImGui::RadioButton(\"Iron\", &rank, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Bronze\", &rank, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Silver\", &rank, 2);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Gold\", &rank, 3);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Platinum\", &rank, 4);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Emerald\", &rank, 5);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Diamond\", &rank, 6);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Master\", &rank, 7);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"GM\", &rank, 8);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Challenger\", &rank, 9);\n\n\t\t\tstatic int tier = 0;\n\t\t\tImGui::RadioButton(\"I\", &tier, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"II\", &tier, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"III\", &tier, 2);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"IV\", &tier, 3);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"None\", &tier, 4);\n\n\t\t\tstatic int queue = 0;\n\t\t\tImGui::RadioButton(\"Solo/Duo\", &queue, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Flex 5v5\", &queue, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Flex 3v3\", &queue, 2);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"TFT\", &queue, 3);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Hyper Roll\", &queue, 4);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Double Up\", &queue, 5);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Arena\", &queue, 6);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"()\", &queue, 7);\n\n\t\t\tImGui::Columns(2, nullptr, false);\n\n\t\t\tif (ImGui::Button(\"Submit##submitRank\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"lol\":{\"rankedLeagueQueue\":\")\";\n\t\t\t\tswitch (queue)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tbody += \"RANKED_SOLO_5x5\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tbody += \"RANKED_FLEX_SR\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbody += \"RANKED_FLEX_TT\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbody += \"RANKED_TFT\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbody += \"RANKED_TFT_TURBO\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 5:\n\t\t\t\t\tbody += \"RANKED_TFT_DOUBLE_UP\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\tbody += \"CHERRY\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 7:\n\t\t\t\t\tbody += \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\n\t\t\t\tbody += R\"(\",\"rankedLeagueTier\":\")\";\n\n\t\t\t\tswitch (rank)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tbody += \"IRON\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tbody += \"BRONZE\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbody += \"SILVER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbody += \"GOLD\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbody += \"PLATINUM\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 5:\n\t\t\t\t\tbody += \"EMERALD\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\tbody += \"DIAMOND\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 7:\n\t\t\t\t\tbody += \"MASTER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tbody += \"GRANDMASTER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 9:\n\t\t\t\t\tbody += \"CHALLENGER\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\n\t\t\t\tbody += R\"(\",\"rankedLeagueDivision\":\")\";\n\n\t\t\t\tswitch (tier)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tbody += \"I\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tbody += \"II\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbody += \"III\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbody += \"IV\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbody += \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\n\t\t\t\tbody += R\"(\"}})\";\n\n\t\t\t\tLCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\", body);\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Empty##emptyRank\"))\n\t\t\t{\n\t\t\t\tLCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\",\n\t\t\t\t\tR\"({\"lol\":{\"rankedLeagueQueue\":\"\",\"rankedLeagueTier\":\"\",\"rankedLeagueDivision\":\"\"}})\");\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Only in the friend's list, not on profile\");\n\n\t\t\tImGui::NextColumn();\n\n\t\t\tif (ImGui::Button(\"Invisible banner\"))\n\t\t\t{\n\t\t\t\tstd::string playerP = GetPlayerPreferences();\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(playerP.c_str(), playerP.c_str() + static_cast<int>(playerP.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\troot[\"bannerAccent\"] = \"2\";\n\t\t\t\t\tLCU::Request(\"POST\", \"/lol-challenges/v1/update-player-preferences/\", root.toStyledString());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Works if last season's rank is unranked\");\n\n\t\t\tImGui::Columns(1);\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic int sendChangeBadges = -99;\n\t\t\tImGui::Text(\"Challenge badges:\");\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Empty\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = -1;\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Copy 1st to all 3\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = -2;\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\"Glitched:\");\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"0##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 0;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"1##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 1;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"2##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 2;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"3##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 3;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"4##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 4;\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"5##glitchedBadges\"))\n\t\t\t{\n\t\t\t\tsendChangeBadges = 5;\n\t\t\t}\n\n\t\t\tif (sendChangeBadges != -99)\n\t\t\t{\n\t\t\t\tstd::string playerP = GetPlayerPreferences();\n\t\t\t\tJson::CharReaderBuilder builder;\n\t\t\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tJSONCPP_STRING err;\n\t\t\t\tJson::Value root;\n\t\t\t\tif (reader->parse(playerP.c_str(), playerP.c_str() + static_cast<int>(playerP.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tJson::Value jsonArray;\n\t\t\t\t\tif (sendChangeBadges != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (size_t i = 0; i < 3; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (sendChangeBadges == -2)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (root[\"challengeIds\"].isArray() && !root[\"challengeIds\"].empty())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tjsonArray.append(root[\"challengeIds\"][0]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tjsonArray.append(sendChangeBadges);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\troot[\"challengeIds\"] = jsonArray;\n\t\t\t\t\tLCU::Request(\"POST\", \"/lol-challenges/v1/update-player-preferences/\", root.toStyledString());\n\t\t\t\t}\n\t\t\t\tsendChangeBadges = -99;\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Text(\"Challenge Points Text: \");\n\n\t\t\tImGui::SameLine();\n\t\t\tstatic char bufChallengePoints[100];\n\t\t\tstatic size_t lastSize = 0;\n\n\t\t\tImGui::SetNextItemWidth(static_cast<float>(S.Window.width / 3));\n\t\t\tImGui::InputText(\"##inputChallengePoints\", bufChallengePoints, IM_ARRAYSIZE(bufChallengePoints));\n\n\t\t\tif (lastSize != strlen(bufChallengePoints))\n\t\t\t{\n\t\t\t\tlastSize = strlen(bufChallengePoints);\n\t\t\t\tLCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\",\n\t\t\t\t\tR\"({\"lol\":{\"challengePoints\":\")\" + std::string(bufChallengePoints) + R\"(\"}})\");\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Set Challenges Rank\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"lol\":{\"challengeCrystalLevel\":\")\";\n\t\t\t\tswitch (rank)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tbody += \"IRON\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tbody += \"BRONZE\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tbody += \"SILVER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tbody += \"GOLD\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbody += \"PLATINUM\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 5:\n\t\t\t\t\tbody += \"EMERALD\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\tbody += \"DIAMOND\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 7:\n\t\t\t\t\tbody += \"MASTER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tbody += \"GRANDMASTER\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 9:\n\t\t\t\t\tbody += \"CHALLENGER\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\n\t\t\t\tLCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\", body + R\"(\"}})\");\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\n\t\t\tImGui::HelpMarker(\"Select the rank using radio buttons above, then press this button.\");\n\n\t\t\tImGui::Separator();\n\t\t\tstatic int masteryLvl;\n\t\t\tImGui::Text(\"Mastery:\");\n\t\t\tImGui::InputInt(\"##inputMasteryLvl:\", &masteryLvl, 1, 100);\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Submit##submitMasteryLvl\"))\n\t\t\t{\n\t\t\t\tstd::string result = LCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me\",\n\t\t\t\t\tR\"({\"lol\":{\"masteryScore\":\")\" + std::to_string(masteryLvl) + \"\\\"}}\");\n\t\t\t\tif (result.find(\"errorCode\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tMessageBoxA(nullptr, result.c_str(), nullptr, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Shown on splash art when hovered over in friend's list\");\n\n\t\t\tImGui::Separator();\n\n\t\t\tstatic int iconID;\n\t\t\tImGui::Text(\"Icon:\");\n\t\t\tImGui::InputInt(\"##inputIcon:\", &iconID, 1, 100);\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Submit##submitIcon\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"profileIconId\":)\" + std::to_string(iconID) + \"}\";\n\t\t\t\tstd::string result = LCU::Request(\"PUT\", \"https://127.0.0.1/lol-summoner/v1/current-summoner/icon\", body);\n\t\t\t\tif (result.find(\"errorCode\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tMessageBoxA(nullptr, result.c_str(), nullptr, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Submit 2##submitIcon2\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"icon\":)\" + std::to_string(iconID) + \"}\";\n\t\t\t\tstd::string result = LCU::Request(\"PUT\", \"https://127.0.0.1/lol-chat/v1/me/\", body);\n\t\t\t\tif (result.find(\"errorCode\") != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tMessageBoxA(nullptr, result.c_str(), nullptr, 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*static int backgroundID;\n\t\t\tImGui::Text(\"Background:\");\n\n\t\t\tImGui::InputInt(\"##inputBackground\", &backgroundID, 1, 100);\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Submit##submitBackground\"))\n\t\t\t{\n\t\t\t\tstd::string body = R\"({\"key\":\"backgroundSkinId\",\"value\":)\" + std::to_string(backgroundID) + \"}\";\n\t\t\t\tstd::string result = LCU::Request(\"POST\", \"https://127.0.0.1/lol-summoner/v1/current-summoner/summoner-profile/\", body);\n\t\t\t}*/\n\n\t\t\tif (ImGui::CollapsingHeader(\"Backgrounds\"))\n\t\t\t{\n\t\t\t\tif (champSkins.empty())\n\t\t\t\t{\n\t\t\t\t\tImGui::Text(\"Skin data is still being fetched\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (ImGui::TreeNode(name.c_str()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (const auto& [fst, snd] : skins)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (ImGui::Button(snd.c_str()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstd::string body = R\"({\"key\":\"backgroundSkinId\",\"value\":)\" + fst + \"}\";\n\t\t\t\t\t\t\t\t\tstd::string result = LCU::Request(\"POST\", \"https://127.0.0.1/lol-summoner/v1/current-summoner/summoner-profile/\",\n\t\t\t\t\t\t\t\t\t\tbody);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tImGui::TreePop();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t}\n\n\tstatic std::string GetPlayerPreferences()\n\t{\n\t\tstd::string challengesData = LCU::Request(\"GET\", \"/lol-challenges/v1/summary-player-data/local-player\");\n\t\tJson::CharReaderBuilder builder;\n\t\tconst std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\tJSONCPP_STRING err;\n\t\tJson::Value root;\n\t\tif (reader->parse(challengesData.c_str(), challengesData.c_str() + static_cast<int>(challengesData.length()), &root, &err))\n\t\t{\n\t\t\tstd::string titleId = root[\"title\"][\"itemId\"].asString();\n\t\t\tstd::string bannerId = root[\"bannerId\"].asString();\n\n\t\t\tstd::string result = \"{\";\n\t\t\tfor (Json::Value::ArrayIndex i = 0; i < root[\"topChallenges\"].size(); i++)\n\t\t\t{\n\t\t\t\tif (i == 0)\n\t\t\t\t\tresult += \"\\\"challengeIds\\\":[\";\n\n\t\t\t\tresult += root[\"topChallenges\"][i][\"id\"].asString();\n\n\t\t\t\tif (i != root[\"topChallenges\"].size() - 1)\n\t\t\t\t\tresult += \",\";\n\t\t\t\telse\n\t\t\t\t\tresult += \"]\";\n\t\t\t}\n\n\t\t\tif (titleId != \"-1\")\n\t\t\t{\n\t\t\t\tif (result.size() != 1)\n\t\t\t\t\tresult += \",\";\n\t\t\t\tresult += R\"(\"title\":\")\" + titleId + \"\\\"\";\n\t\t\t}\n\n\t\t\tif (!bannerId.empty())\n\t\t\t{\n\t\t\t\tif (result.size() != 1)\n\t\t\t\t\tresult += \",\";\n\t\t\t\tresult += R\"(\"bannerAccent\":\")\" + bannerId + \"\\\"\";\n\t\t\t}\n\t\t\tresult += \"}\";\n\n\t\t\treturn result;\n\t\t}\n\t\treturn \"\";\n\t}\n};\n"
  },
  {
    "path": "KBotExt/SettingsTab.h",
    "content": "#pragma once\n\n#include \"Includes.h\"\n#include \"Misc.h\"\n#include \"Config.h\"\n\nclass SettingsTab\n{\npublic:\n\tstatic void Render()\n\t{\n\t\tusing tRegCreateKeyExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass,\n\t\t\tDWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult,\n\t\t\tLPDWORD lpdwDisposition);\n\t\tstatic auto RegCreateKeyExA = reinterpret_cast<tRegCreateKeyExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegCreateKeyExA\"));\n\n\t\tusing tRegOpenKeyExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,\n\t\t\tREGSAM samDesired, PHKEY phkResult);\n\t\tstatic auto RegOpenKeyExA = reinterpret_cast<tRegOpenKeyExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegOpenKeyExA\"));\n\n\t\tusing tRegQueryValueExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpValueName,\n\t\t\tLPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbDatan);\n\t\tstatic auto RegQueryValueExA = reinterpret_cast<tRegQueryValueExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegQueryValueExA\"));\n\n\t\tusing tRegSetValueExA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpValueName, DWORD Reserved,\n\t\t\tDWORD dwType, const BYTE* lpData, DWORD cbData);\n\t\tstatic auto RegSetValueExA = reinterpret_cast<tRegSetValueExA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegSetValueExA\"));\n\n\t\tusing tRegDeleteValueA = LSTATUS(WINAPI*)(HKEY hKey, LPCSTR lpValueName);\n\t\tstatic auto RegDeleteValueA = reinterpret_cast<tRegDeleteValueA>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegDeleteValueA\"));\n\n\t\tusing tRegCloseKey = LSTATUS(WINAPI*)(HKEY hKe);\n\t\tstatic auto RegCloseKey = reinterpret_cast<tRegCloseKey>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"RegCloseKey\"));\n\n\t\tstatic bool once = true;\n\t\tif (ImGui::BeginTabItem(\"Settings\"))\n\t\t{\n\t\t\tif (once)\n\t\t\t{\n\t\t\t\tonce = false;\n\t\t\t\tHKEY hkResult;\n\t\t\t\tif (RegOpenKeyExA(\n\t\t\t\t\tHKEY_LOCAL_MACHINE, R\"(Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\LeagueClientUx.exe)\", 0,\n\t\t\t\t\tKEY_READ, &hkResult) == ERROR_SUCCESS)\n\t\t\t\t{\n\t\t\t\t\tchar buffer[MAX_PATH];\n\t\t\t\t\tDWORD dwLen = sizeof(buffer);\n\t\t\t\t\tif (const LSTATUS regQuery = RegQueryValueExA(hkResult, \"debugger\", nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer), &dwLen);\n\t\t\t\t\t\tregQuery == ERROR_SUCCESS)\n\t\t\t\t\t{\n\t\t\t\t\t\tS.currentDebugger = std::string(buffer, dwLen);\n\t\t\t\t\t}\n\t\t\t\t\telse if (regQuery == ERROR_FILE_NOT_FOUND)\n\t\t\t\t\t{\n\t\t\t\t\t\tS.currentDebugger = \"Nothing\";\n\t\t\t\t\t\tS.debugger = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tS.currentDebugger = \"Failed, error code \" + regQuery;\n\t\t\t\t\t}\n\t\t\t\t\tRegCloseKey(hkResult);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tS.currentDebugger = \"Error\";\n\t\t\t}\n\t\t\tstatic std::string result;\n\n\t\t\tImGui::Checkbox(\"Auto-rename\", &S.autoRename);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Automatically renames the program on launch\");\n\n\t\t\tif (ImGui::Checkbox(\"Stream proof\", &S.streamProof))\n\t\t\t{\n\t\t\t\tif (S.streamProof)\n\t\t\t\t\tSetWindowDisplayAffinity(S.hwnd, WDA_EXCLUDEFROMCAPTURE);\n\t\t\t\telse\n\t\t\t\t\tSetWindowDisplayAffinity(S.hwnd, WDA_NONE);\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Hides the program in recordings and screenshots\");\n\n\t\t\tImGui::Checkbox(\"Notify about prereleases\", &S.checkPrerelease);\n\n\t\t\tImGui::Checkbox(\"Launch client without admin\", &S.noAdmin);\n\n\t\t\tif (ImGui::Checkbox(\"Register debugger IFEO\", &S.debugger))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Debugger IFEO\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tHKEY hkResult;\n\t\t\t\t\tif (const LSTATUS regCreate = RegCreateKeyExA(HKEY_LOCAL_MACHINE,\n\t\t\t\t\t\tR\"(Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\LeagueClientUx.exe)\",\n\t\t\t\t\t\t0, nullptr, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, nullptr, &hkResult,\n\t\t\t\t\t\tnullptr); regCreate == ERROR_SUCCESS)\n\t\t\t\t\t{\n\t\t\t\t\t\tchar* buffer[MAX_PATH];\n\t\t\t\t\t\tDWORD bufferLen = sizeof(buffer);\n\n\t\t\t\t\t\tchar filePath[MAX_PATH + 1];\n\t\t\t\t\t\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\t\t\t\t\t\tstatic auto pGetModuleFileNameA = (decltype(&GetModuleFileNameA))GetProcAddress(kernel32, \"GetModuleFileNameA\");\n\t\t\t\t\t\tpGetModuleFileNameA(nullptr, filePath, MAX_PATH);\n\t\t\t\t\t\tconst auto len = static_cast<DWORD>(strlen(filePath) + 1); // bugprone-misplaced-widening-cast?\n\n\t\t\t\t\t\tif (const LSTATUS regQuery = RegQueryValueExA(hkResult, \"debugger\", nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer),\n\t\t\t\t\t\t\t&bufferLen); regQuery == ERROR_SUCCESS || regQuery == ERROR_FILE_NOT_FOUND)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (S.debugger)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tauto messageBoxStatus = IDYES;\n\t\t\t\t\t\t\t\tif (S.autoRename || S.noAdmin)\n\t\t\t\t\t\t\t\t\tmessageBoxStatus = MessageBoxA(nullptr, \"Having \\\"Auto-rename\\\" or \\\"Launch client without admin\\\" \"\n\t\t\t\t\t\t\t\t\t\t\"enabled with \\\"debugger IFEO\\\" will prevent League client from starting\\n\\n\"\n\t\t\t\t\t\t\t\t\t\t\"Do you wish to continue?\", \"Warning\", MB_YESNO | MB_SETFOREGROUND);\n\n\t\t\t\t\t\t\t\tif (messageBoxStatus == IDYES)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (RegSetValueExA(hkResult, \"debugger\", 0, REG_SZ, reinterpret_cast<const BYTE*>(filePath), len) == ERROR_SUCCESS)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tS.currentDebugger = filePath;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tS.debugger = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (regQuery == ERROR_SUCCESS)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tRegDeleteValueA(hkResult, \"debugger\");\n\t\t\t\t\t\t\t\tS.currentDebugger = \"Nothing\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tRegCloseKey(hkResult);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::HelpMarker(\"Allows for client traffic analysis via a web debugging proxy such as Fiddler.\"\n\t\t\t\t\"Disable before deleting the program. Doesn't work when \\\"Auto-rename\\\" or \\\"Launch client without admin\\\" are enabled.\");\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\"| Hooked to: %s\", S.currentDebugger.c_str());\n\n\t\t\tif (ImGui::Button(\"Clean logs\"))\n\t\t\t{\n\t\t\t\tif (MessageBoxA(nullptr, \"Are you sure?\", \"Cleaning logs\", MB_OKCANCEL) == IDOK)\n\t\t\t\t{\n\t\t\t\t\tresult = Misc::ClearLogs();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tif (ImGui::Button(\"Force close client\"))\n\t\t\t\tMisc::TaskKillLeague();\n\n\t\t\tstatic char bufLeaguePath[MAX_PATH];\n\t\t\tstd::ranges::copy(S.leaguePath, bufLeaguePath);\n\t\t\tImGui::Text(\"League path:\");\n\t\t\tImGui::InputText(\"##leaguePath\", bufLeaguePath, MAX_PATH);\n\t\t\tS.leaguePath = bufLeaguePath;\n\n\t\t\tImGui::SameLine();\n\n\t\t\tif (ImGui::Button(\"Try to auto detect path\"))\n\t\t\t{\n\t\t\t\tusing tSHGetFolderPathW = HRESULT(WINAPI*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);\n\t\t\t\tconst auto SHGetFolderPathW = reinterpret_cast<tSHGetFolderPathW>(GetProcAddress(LoadLibraryW(L\"shell32.dll\"), \"SHGetFolderPathW\"));\n\n\t\t\t\tTCHAR szPath[MAX_PATH];\n\t\t\t\tif (SUCCEEDED(SHGetFolderPathW(NULL, 0x23/*CSIDL_COMMON_APPDATA*/, NULL, 0, szPath)))\n\t\t\t\t{\n\t\t\t\t\tstd::filesystem::path programData(szPath);\n\t\t\t\t\tauto productSettingPath = programData / \"Riot Games\\\\Metadata\\\\league_of_legends.live\\\\league_of_legends.live.product_settings.yaml\";\n\t\t\t\t\tif (std::filesystem::exists(productSettingPath))\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ifstream fileStream(productSettingPath);\n\t\t\t\t\t\tif (fileStream.is_open())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::string line;\n\t\t\t\t\t\t\twhile (std::getline(fileStream, line))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (line.contains(\"product_install_full_path: \"))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (std::size_t pos = line.find(\":\"); pos != std::string::npos)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstd::string value = line.substr(pos + 2);\n\t\t\t\t\t\t\t\t\t\tvalue.erase(std::remove(value.begin(), value.end(), '\\\"'), value.end());\n\t\t\t\t\t\t\t\t\t\tsize_t found;\n\t\t\t\t\t\t\t\t\t\twhile ((found = value.find(\"\\\\\\\\\")) != std::string::npos)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tvalue.replace(found, 2, \"/\");\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tif (value.back() != '/')\n\t\t\t\t\t\t\t\t\t\t\tvalue += '/';\n\t\t\t\t\t\t\t\t\t\tS.leaguePath = value;\n\t\t\t\t\t\t\t\t\t\tstd::fill(bufLeaguePath, bufLeaguePath + MAX_PATH, 0);\n\t\t\t\t\t\t\t\t\t\tstd::ranges::copy(S.leaguePath, bufLeaguePath);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfileStream.close();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::Separator();\n\n\t\t\tImGui::Text(\"Font Scale:\");\n\t\t\tif (ImGui::SliderFloat(\"##fontScaleSlider\", &S.fontScale, 0.4f, 4.f, \"%0.1f\"))\n\t\t\t{\n\t\t\t\tImGuiIO& io = ImGui::GetIO();\n\t\t\t\tio.FontGlobalScale = S.fontScale;\n\t\t\t}\n\n\t\t\tif (ImGui::Button(\"Reset window size\"))\n\t\t\t{\n\t\t\t\tS.Window.width = 730;\n\t\t\t\tS.Window.height = 530;\n\t\t\t\tSetWindowPos(S.hwnd, nullptr, 0, 0, S.Window.width, S.Window.height, SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);\n\n\t\t\t\tS.fontScale = 1.f;\n\t\t\t\tImGuiIO& io = ImGui::GetIO();\n\t\t\t\tio.FontGlobalScale = S.fontScale;\n\n\t\t\t\tConfig::Save();\n\t\t\t}\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(std::format(\"{0}x{1}\", S.Window.width, S.Window.height).c_str());\n\n\t\t\tImGui::Separator();\n\t\t\tImGui::Text(\"Program's version: %s | Latest version: %s\",\n\t\t\t\tMisc::programVersion.c_str(), Misc::latestVersion.c_str());\n\t\t\tImGui::Text(\"GitHub repository:\");\n\t\t\tImGui::TextURL(\"Click me!\", \"https://github.com/KebsCS/KBotExt\", 1, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::Text(\"| Discord server:\");\n\t\t\tImGui::TextURL(\"Click me!\", \"https://discord.gg/qMmPBFpj2n\", 1, 0);\n\n\t\t\tif (!result.empty())\n\t\t\t\tImGui::Separator();\n\t\t\tImGui::TextWrapped(result.c_str());\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t\tonce = true;\n\t}\n};\n"
  },
  {
    "path": "KBotExt/SkinsTab.h",
    "content": "#pragma once\n\n#include \"Definitions.h\"\n#include \"Includes.h\"\n#include \"LCU.h\"\n\nclass SkinsTab\n{\npublic:\n\tstatic void Render()\n\t{\n\t\tstatic bool bOnOpen = true;\n\t\tstatic bool bSortOnOpen = false;\n\n\t\tif (ImGui::BeginTabItem(\"Skins\"))\n\t\t{\n\t\t\tImGui::Text(\"Sort by: \");\n\t\t\tImGui::SameLine();\n\n\t\t\tstatic int iSort = 0;\n\t\t\tstatic int iLastSort = -1;\n\t\t\tImGui::RadioButton(\"Alphabetically\", &iSort, 0);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"Purchase date\", &iSort, 1);\n\t\t\tImGui::SameLine();\n\t\t\tImGui::RadioButton(\"ID\", &iSort, 2);\n\n\t\t\tif (bOnOpen)\n\t\t\t{\n\t\t\t\tbOnOpen = false;\n\t\t\t\tbSortOnOpen = true;\n\t\t\t\townedSkins.clear();\n\n\t\t\t\tstatic Json::Value root;\n\t\t\t\tstatic Json::CharReaderBuilder builder;\n\t\t\t\tstatic const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());\n\t\t\t\tstatic JSONCPP_STRING err;\n\n\t\t\t\tstd::string getSkins = LCU::Request(\"GET\", \"https://127.0.0.1/lol-inventory/v2/inventory/CHAMPION_SKIN\");\n\n\t\t\t\tif (reader->parse(getSkins.c_str(), getSkins.c_str() + static_cast<int>(getSkins.length()), &root, &err))\n\t\t\t\t{\n\t\t\t\t\tif (root.isArray())\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto& i : root)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSkin skin;\n\n\t\t\t\t\t\t\tskin.inventoryType = i[\"inventoryType\"].asString();\n\t\t\t\t\t\t\tskin.itemId = i[\"itemId\"].asInt();\n\t\t\t\t\t\t\tskin.ownershipType = i[\"ownershipType\"].asString();\n\t\t\t\t\t\t\tskin.isVintage = i[\"payload\"][\"isVintage\"].asBool();\n\n\t\t\t\t\t\t\tstd::string purchase = i[\"purchaseDate\"].asString();\n\t\t\t\t\t\t\tif (purchase.find('-') == std::string::npos && purchase.find(':') == std::string::npos)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsscanf_s(purchase.c_str(), \"%04d%02d%02dT%02d%02d%02d\",\n\t\t\t\t\t\t\t\t\t&skin.purchaseDate.tm_year, &skin.purchaseDate.tm_mon, &skin.purchaseDate.tm_mday,\n\t\t\t\t\t\t\t\t\t&skin.purchaseDate.tm_hour, &skin.purchaseDate.tm_min, &skin.purchaseDate.tm_sec);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsscanf_s(purchase.c_str(), \"%04d-%02d-%02dT%02d:%02d:%02d\",\n\t\t\t\t\t\t\t\t\t&skin.purchaseDate.tm_year, &skin.purchaseDate.tm_mon, &skin.purchaseDate.tm_mday,\n\t\t\t\t\t\t\t\t\t&skin.purchaseDate.tm_hour, &skin.purchaseDate.tm_min, &skin.purchaseDate.tm_sec);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tskin.purchaseDate.tm_year -= 1901;\n\t\t\t\t\t\t\tskin.purchaseDate.tm_mon -= 1;\n\n\t\t\t\t\t\t\tskin.quantity = i[\"quantity\"].asInt();\n\t\t\t\t\t\t\tskin.uuid = i[\"uuid\"].asString();\n\n\t\t\t\t\t\t\tif (!champSkins.empty())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\t\t\tfor (const auto& [key, name, skins] : champSkins)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor (const auto& [fst, snd] : skins)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (skin.itemId == std::stoi(fst))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tskin.name = snd;\n\t\t\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (found)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\townedSkins.emplace_back(skin);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((iLastSort != iSort) || bSortOnOpen)\n\t\t\t{\n\t\t\t\tbSortOnOpen = false;\n\t\t\t\tiLastSort = iSort;\n\t\t\t\tswitch (iSort)\n\t\t\t\t{\n\t\t\t\t\t// alphabetically\n\t\t\t\tcase 0:\n\t\t\t\t\tstd::ranges::sort(ownedSkins, [](const Skin& lhs, const Skin& rhs) {\n\t\t\t\t\t\treturn lhs.name < rhs.name;\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t\t// purchase date\n\t\t\t\tcase 1:\n\t\t\t\t\tstd::ranges::sort(ownedSkins, [](Skin lhs, Skin rhs) {\n\t\t\t\t\t\treturn mktime(&lhs.purchaseDate) < mktime(&rhs.purchaseDate);\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t\t// id\n\t\t\t\tcase 2:\n\t\t\t\t\tstd::ranges::sort(ownedSkins, [](const Skin& lhs, const Skin& rhs) {\n\t\t\t\t\t\treturn lhs.itemId < rhs.itemId;\n\t\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui::SameLine();\n\t\t\tstatic char allNamesSeparator[64] = \",\";\n\t\t\tif (ImGui::Button(\"Copy names to clipboard##skinsTab\"))\n\t\t\t{\n\t\t\t\tstd::string allNames;\n\t\t\t\tfor (const auto& [name, inventoryType, itemId, ownershipType, isVintage, purchaseDate, quantity, uuid] : ownedSkins)\n\t\t\t\t{\n\t\t\t\t\tif (name.empty())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tallNames += name + allNamesSeparator;\n\t\t\t\t}\n\t\t\t\tUtils::CopyToClipboard(allNames);\n\t\t\t}\n\t\t\tImGui::SameLine();\n\n\t\t\tconst ImVec2 label_size = ImGui::CalcTextSize(\"W\", nullptr, true);\n\t\t\tImGui::InputTextMultiline(\"##separatorSkinsTab\", allNamesSeparator, IM_ARRAYSIZE(allNamesSeparator),\n\t\t\t\tImVec2(0, label_size.y + ImGui::GetStyle().FramePadding.y * 2.0f), ImGuiInputTextFlags_AllowTabInput);\n\n\t\t\tImGui::Separator();\n\t\t\tImGui::Text(\"Skins owned: %d\", ownedSkins.size());\n\n\t\t\tfor (const auto& [name, inventoryType, itemId, ownershipType, isVintage, purchaseDate, quantity, uuid] : ownedSkins)\n\t\t\t{\n\t\t\t\tchar timeBuff[50];\n\t\t\t\tstrftime(timeBuff, sizeof(timeBuff), \"%G-%m-%d %H:%M:%S\", &purchaseDate); // cert-err33-c -> The value of this function should be used\n\n\t\t\t\tstd::string inputId = \"skinInput\";\n\t\t\t\tinputId.append(std::to_string(itemId));\n\t\t\t\tchar input[512];\n\t\t\t\tstrcpy_s(input, std::format(R\"(name: {}\ninventoryType: {}\nitemId: {}\nownershipType: {}\nisVintage: {}\npurchaseDate: {}\nquantity: {}\nuuid: {})\", name, inventoryType, itemId, ownershipType, isVintage, timeBuff, quantity, uuid).c_str());\n\t\t\t\tImGui::PushID(inputId.c_str());\n\t\t\t\tImGui::InputTextMultiline(\"\", input, IM_ARRAYSIZE(input), ImVec2(ImGui::GetWindowSize().x, 0), ImGuiInputTextFlags_ReadOnly);\n\t\t\t\tImGui::PopID();\n\t\t\t}\n\n\t\t\tImGui::EndTabItem();\n\t\t}\n\t\telse\n\t\t\tbOnOpen = true;\n\t}\n};\n"
  },
  {
    "path": "KBotExt/Utils.cpp",
    "content": "#include <locale>\n#include <codecvt>\n#include <sstream>\n#include <filesystem>\n#include <array>\n#include <cwctype>\n#include <random>\n//URLDownloadToFileA\n#include <urlmon.h>\n#pragma comment(lib, \"urlmon.lib\")\n\n#include \"Utils.h\"\n\nint Utils::RandomInt(const int min, const int max)\n{\n\tstd::random_device rd;\n\tstd::mt19937 gen(rd());\n\tstd::uniform_int_distribution dist(min, max);\n\n\treturn dist(gen);\n}\n\nstd::string Utils::ToLower(std::string str)\n{\n\tstd::ranges::transform(str, str.begin(),\n\t\t[](const unsigned char c) { return static_cast<char>(std::tolower(c)); });\n\treturn str;\n}\n\nstd::wstring Utils::ToLower(std::wstring wstr)\n{\n\tstd::ranges::transform(wstr, wstr.begin(), std::towlower);\n\treturn wstr;\n}\n\nstd::string Utils::ToUpper(std::string str)\n{\n\tstd::ranges::transform(str, str.begin(),\n\t\t[](const unsigned char c) { return static_cast<char>(std::toupper(c)); });\n\treturn str;\n}\n\nstd::wstring Utils::ToUpper(std::wstring wstr)\n{\n\tstd::ranges::transform(wstr, wstr.begin(), std::towupper);\n\treturn wstr;\n}\n\nbool Utils::StringContains(std::string strA, std::string strB, const bool ignoreCase)\n{\n\tif (strA.empty() || strB.empty())\n\t\treturn true;\n\n\tif (ignoreCase)\n\t{\n\t\tstrA = ToLower(strA);\n\t\tstrB = ToLower(strB);\n\t}\n\n\tif (strA.find(strB) != std::string::npos)\n\t\treturn true;\n\n\treturn false;\n}\n\nbool Utils::StringContains(std::wstring wstrA, std::wstring wstrB, const bool ignoreCase)\n{\n\tif (wstrA.empty() || wstrB.empty())\n\t\treturn true;\n\n\tif (ignoreCase)\n\t{\n\t\twstrA = ToLower(wstrA);\n\t\twstrB = ToLower(wstrB);\n\t}\n\n\tif (wstrA.find(wstrB) != std::wstring::npos)\n\t\treturn true;\n\n\treturn false;\n}\n\nstd::string Utils::WstringToString(const std::wstring& wstr)\n{\n\tstd::wstring_convert<std::codecvt_utf8<wchar_t>> converter;\n\treturn converter.to_bytes(wstr);\n}\n\nstd::wstring Utils::StringToWstring(const std::string& str)\n{\n\ttry\n\t{\n\t\tstd::wstring_convert<std::codecvt_utf8<wchar_t>> converter;\n\t\treturn converter.from_bytes(str);\n\t}\n\tcatch (std::range_error) // ThrowByValueCatchByReference\n\t{\n\t\tstd::wostringstream s;\n\t\ts << str.c_str();\n\t\treturn s.str();\n\t}\n}\n\nstd::vector<std::string> Utils::StringSplit(std::string str, const std::string& separator, const int max)\n{\n\tint count = 0;\n\tsize_t pos;\n\tstd::vector<std::string> vec;\n\twhile ((pos = str.find(separator)) != std::string::npos)\n\t{\n\t\tif (max != -1 && count == max)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcount++;\n\t\tstd::string token = str.substr(0, pos);\n\t\tvec.emplace_back(token);\n\t\tstr.erase(0, pos + separator.length());\n\t}\n\tvec.emplace_back(str);\n\treturn vec;\n}\n\nstd::string Utils::RandomString(const size_t size)\n{\n\tstd::string str;\n\n\tfor (size_t i = 0; i < size; i++)\n\t\tstr += std::to_string(RandomInt(0, 1) ? RandomInt(48, 57) : RandomInt(97, 122));\n\n\treturn str;\n}\n\nstd::wstring Utils::RandomWString(const size_t size, const std::pair<unsigned, unsigned> range)\n{\n\tstd::wstring str;\n\n\tif (range.first == 0 && range.second == 0)\n\t{\n\t\tfor (size_t i = 0; i < size; i++)\n\t\t\tstr += std::to_wstring(RandomInt(0, 1) ? RandomInt(48, 57) : RandomInt(97, 122));\n\t}\n\telse\n\t{\n\t\tfor (size_t i = 0; i < size; i++)\n\t\t\tstr += static_cast<wchar_t>(RandomInt(range.first, range.second));\n\t}\n\n\treturn str;\n}\n\nvoid Utils::CopyToClipboard(const std::string& text)\n{\n\tif (!OpenClipboard(nullptr))\n\t\treturn;\n\tconst int wbufLen = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, nullptr, 0);\n\tconst HGLOBAL wbufHandle = GlobalAlloc(GMEM_MOVEABLE, static_cast<SIZE_T>(wbufLen) * sizeof(WCHAR));\n\tif (wbufHandle == nullptr)\n\t{\n\t\tCloseClipboard();\n\t\treturn;\n\t}\n\tconst auto wbufGlobal = static_cast<WCHAR*>(GlobalLock(wbufHandle));\n\tMultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, wbufGlobal, wbufLen);\n\tGlobalUnlock(wbufHandle);\n\tEmptyClipboard();\n\tif (SetClipboardData(CF_UNICODETEXT, wbufHandle) == nullptr)\n\t\tGlobalFree(wbufHandle);\n\tCloseClipboard();\n}\n\nbool Utils::DownloadFile(std::string fileName, const std::string& directory, const std::string& url)\n{\n\t// Create folder if it doesn't exists\n\tif (!std::filesystem::exists(directory))\n\t\tstd::filesystem::create_directory(directory);\n\tif (fileName[0] == '\\\\')\n\t\tfileName.erase(0);\n\tconst std::string file = directory + \"\\\\\" + fileName;\n\n\t// Don't download if file already exists\n\tif (std::filesystem::exists(file))\n\t\treturn true;\n\n\tconst std::string fullPath = std::filesystem::current_path().string() + \"\\\\\" + file;\n\tconst std::string toDownload = url + fileName;\n\n\t// Download file\n\n\tif (const HRESULT result = URLDownloadToFileA(nullptr, toDownload.c_str(), fullPath.c_str(), 0, nullptr); result != S_OK)\n\t\treturn false;\n\treturn true;\n}\n\nbool Utils::ContainsOnlyASCII(const std::string& buff)\n{\n\tfor (const char i : buff)\n\t{\n\t\tif (i == 0)\n\t\t\treturn true;\n\t\tif (static_cast<unsigned char>(i) > 127)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\nstd::string Utils::Utf8Encode(const std::wstring& wstr)\n{\n\tstd::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv;\n\treturn conv.to_bytes(wstr);\n}\n\nstd::string Utils::Exec(const char* cmd)\n{\n\tstd::array<char, 128> buffer;\n\tstd::string result;\n\tconst std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(cmd, \"r\"), _pclose);\n\tif (!pipe)\n\t{\n\t\tthrow std::runtime_error(\"popen() failed!\");\n\t}\n\twhile (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe.get()) != nullptr)\n\t{\n\t\tresult += buffer.data();\n\t}\n\treturn result;\n}\n\nstd::string Utils::RenameExe()\n{\n\tchar szExeFileName[MAX_PATH];\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\tstatic auto pGetModuleFileNameA = (decltype(&GetModuleFileNameA))GetProcAddress(kernel32, \"GetModuleFileNameA\");\n\tpGetModuleFileNameA(nullptr, szExeFileName, MAX_PATH);\n\tconst auto path = std::string(szExeFileName);\n\tconst std::string exe = path.substr(path.find_last_of('\\\\') + 1, path.size());\n\tstd::string newName = RandomString(RandomInt(5, 10));\n\tnewName += \".exe\";\n\tif (!rename(exe.c_str(), newName.c_str()))\n\t\treturn newName;\n\treturn \"\";\n}\n\nvoid Utils::OpenUrl(const char* url, const char* args, int flags)\n{\n\tstatic decltype(&ShellExecuteA) pShellExecuteA = nullptr;\n\n\tif (!pShellExecuteA) {\n\t\tHMODULE shell32 = LoadLibraryA(\"shell32.dll\");\n\t\t(LPVOID&)pShellExecuteA = GetProcAddress(shell32, \"ShellExecuteA\");\n\t}\n\n\tif (pShellExecuteA)\n\t\tpShellExecuteA(nullptr, \"open\", url, args, nullptr, flags);\n}\n\nvoid Utils::OpenUrl(const wchar_t* url, const wchar_t* args, int flags)\n{\n\tstatic decltype(&ShellExecuteW) pShellExecuteW = nullptr;\n\n\tif (!pShellExecuteW) {\n\t\tHMODULE shell32 = LoadLibraryA(\"shell32.dll\");\n\t\t(LPVOID&)pShellExecuteW = GetProcAddress(shell32, \"ShellExecuteW\");\n\t}\n\n\tif (pShellExecuteW)\n\t\tpShellExecuteW(NULL, L\"open\", url, args, NULL, flags);\n}\n\nbool Utils::HideFile(const std::string& file)\n{\n\tif (const int attr = GetFileAttributesA(file.c_str()); (attr & FILE_ATTRIBUTE_HIDDEN) == 0)\n\t{\n\t\tSetFileAttributesA(file.c_str(), attr | FILE_ATTRIBUTE_HIDDEN);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nbool Utils::RunAsUser(const LPCWSTR lpApplicationName, const LPWSTR lpCommandLine)\n{\n\tusing tOpenProcessToken = BOOL(WINAPI*)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);\n\tstatic auto OpenProcessToken = reinterpret_cast<tOpenProcessToken>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"OpenProcessToken\"));\n\n\tHANDLE hProcessToken = nullptr;\n\tif (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken))\n\t{\n\t\t// fails if current process isn't elevated\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tusing tLookupPrivilegeValueW = BOOL(WINAPI*)(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);\n\tstatic auto LookupPrivilegeValueW = reinterpret_cast<tLookupPrivilegeValueW>(GetProcAddress(\n\t\tLoadLibraryW(L\"advapi32.dll\"), \"LookupPrivilegeValueW\"));\n\n\tTOKEN_PRIVILEGES tkp = { 0 };\n\ttkp.PrivilegeCount = 1;\n\tif (!LookupPrivilegeValueW(nullptr, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid))\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tusing tAdjustTokenPrivileges = BOOL(WINAPI*)(HANDLE TokenHandle, BOOL DisableAllPrivileges,\n\t\tPTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState,\n\t\tPDWORD ReturnLength);\n\tstatic auto AdjustTokenPrivileges = reinterpret_cast<tAdjustTokenPrivileges>(GetProcAddress(\n\t\tLoadLibraryW(L\"advapi32.dll\"), \"AdjustTokenPrivileges\"));\n\n\tDWORD returnLength = 0;\n\ttkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n\tif (!AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, nullptr, &returnLength))\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tusing tGetShellWindow = HWND(WINAPI*)();\n\tstatic auto GetShellWindow = reinterpret_cast<tGetShellWindow>(GetProcAddress(LoadLibraryW(L\"user32.dll\"), \"GetShellWindow\"));\n\n\tconst HWND hwnd = GetShellWindow();\n\tif (!hwnd)\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tDWORD pid = 0;\n\tGetWindowThreadProcessId(hwnd, &pid);\n\tif (!pid)\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tstatic HMODULE kernel32 = GetModuleHandleA(\"kernel32\");\n\tstatic auto pOpenProcess = (decltype(&OpenProcess))GetProcAddress(kernel32, \"OpenProcess\");\n\tconst HANDLE hShellProcess = pOpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);\n\tif (!hShellProcess)\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\treturn false;\n\t}\n\n\tHANDLE hShellProcessToken = nullptr;\n\tif (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken))\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\tCloseHandle(hShellProcess);\n\t\tCloseHandle(hShellProcessToken);\n\t\treturn false;\n\t}\n\n\tusing tDuplicateTokenEx = BOOL(WINAPI*)(HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES pTokenAttributes,\n\t\tSECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken);\n\tstatic auto DuplicateTokenEx = reinterpret_cast<tDuplicateTokenEx>(GetProcAddress(LoadLibraryW(L\"advapi32.dll\"), \"DuplicateTokenEx\"));\n\n\tHANDLE hPrimaryToken = nullptr;\n\tif (!DuplicateTokenEx(hShellProcessToken, TOKEN_ALL_ACCESS, nullptr, SecurityImpersonation, TokenPrimary, &hPrimaryToken))\n\t{\n\t\tCloseHandle(hProcessToken);\n\t\tCloseHandle(hShellProcess);\n\t\tCloseHandle(hShellProcessToken);\n\t\tCloseHandle(hPrimaryToken);\n\t\treturn false;\n\t}\n\n\tusing tCreateProcessWithTokenW = BOOL(WINAPI*)(HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName,\n\t\tLPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,\n\t\tLPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);\n\tstatic auto CreateProcessWithTokenW = reinterpret_cast<tCreateProcessWithTokenW>(GetProcAddress(\n\t\tLoadLibraryW(L\"advapi32.dll\"), \"CreateProcessWithTokenW\"));\n\n\tPROCESS_INFORMATION pi = { nullptr };\n\tSTARTUPINFOW si = { 0 };\n\tsi.cb = sizeof(si);\n\tsi.wShowWindow = SW_SHOWNORMAL;\n\tsi.dwFlags = STARTF_USESHOWWINDOW;\n\tif (!CreateProcessWithTokenW(hPrimaryToken, 0, lpApplicationName, lpCommandLine, 0/*DETACHED_PROCESS - error 87*/, nullptr, nullptr, &si, &pi))\n\t{\n\t\t//printf(\"%d\",GetLastError());\n\t\tCloseHandle(hProcessToken);\n\t\tCloseHandle(hShellProcess);\n\t\tCloseHandle(hShellProcessToken);\n\t\tCloseHandle(hPrimaryToken);\n\t\tCloseHandle(pi.hProcess);\n\t\treturn false;\n\t}\n\n\tCloseHandle(hProcessToken);\n\tCloseHandle(hShellProcess);\n\tCloseHandle(hShellProcessToken);\n\tCloseHandle(hPrimaryToken);\n\tCloseHandle(pi.hProcess);\n\treturn true;\n}\n\ncpr::Header Utils::StringToHeader(const std::string& str)\n{\n\tcpr::Header header;\n\tfor (const auto& line : StringSplit(str, \"\\r\\n\"))\n\t{\n\t\tif (const auto index = line.find(\": \", 0); index != std::string::npos)\n\t\t{\n\t\t\theader.insert({ line.substr(0, index), line.substr(index + 2) });\n\t\t}\n\t}\n\treturn header;\n}"
  },
  {
    "path": "KBotExt/Utils.h",
    "content": "#pragma once\n\n#include <cpr/cpr.h>\n\nclass Utils\n{\npublic:\n\tUtils() = default;\n\t~Utils() = default;\n\n\tstatic int RandomInt(int min, int max);\n\n\tstatic std::string ToLower(std::string str);\n\tstatic std::wstring ToLower(std::wstring wstr);\n\n\tstatic std::string ToUpper(std::string str);\n\tstatic std::wstring ToUpper(std::wstring wstr);\n\n\t//check if strA contains strB\n\tstatic bool StringContains(std::string strA, std::string strB, bool ignoreCase = false);\n\tstatic bool StringContains(std::wstring strA, std::wstring strB, bool ignoreCase = false);\n\n\tstatic std::wstring StringToWstring(const std::string& str);\n\tstatic std::string WstringToString(const std::wstring& wstr);\n\n\tstatic std::vector<std::string> StringSplit(std::string str, const std::string& separator, int max = -1);\n\n\tstatic std::string RandomString(size_t size);\n\tstatic std::wstring RandomWString(size_t size, std::pair<unsigned, unsigned> range = { 0, 0 });\n\n\tstatic void CopyToClipboard(const std::string& text);\n\n\tstatic bool DownloadFile(std::string fileName, const std::string& directory, const std::string& url);\n\n\tstatic bool ContainsOnlyASCII(const std::string& buff);\n\n\tstatic std::string Utf8Encode(const std::wstring& wstr);\n\n\tstatic std::string Exec(const char* cmd);\n\n\tstatic std::string RenameExe();\n\n\tstatic void OpenUrl(const char* url, const char* args = nullptr, int flags = SW_SHOWNORMAL);\n\tstatic void OpenUrl(const wchar_t* url, const wchar_t* args = nullptr, int flags = SW_SHOWNORMAL);\n\n\t// adds the \"Hidden\" attribute to a file\n\tstatic bool HideFile(const std::string& file);\n\n\tstatic bool RunAsUser(LPCWSTR lpApplicationName, LPWSTR lpCommandLine);\n\n\tstatic cpr::Header StringToHeader(const std::string& str);\n};\n"
  },
  {
    "path": "KBotExt/base64.h",
    "content": "#pragma once\n\n#include <string>\n\nclass Base64\n{\n\tstd::string base64_chars =\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\t\"abcdefghijklmnopqrstuvwxyz\"\n\t\t\"0123456789+/\";\n\npublic:\n\tstatic bool is_base64(const unsigned char c)\n\t{\n\t\treturn isalnum(c) || c == '+' || c == '/';\n\t}\n\n\tstd::string Encode(const unsigned char* bytes_to_encode, unsigned int in_len)\n\t{\n\t\tstd::string ret;\n\t\tint i = 0;\n\t\tunsigned char char_array_3[3];\n\t\tunsigned char char_array_4[4];\n\n\t\twhile (in_len--)\n\t\t{\n\t\t\tchar_array_3[i++] = *(bytes_to_encode++);\n\t\t\tif (i == 3)\n\t\t\t{\n\t\t\t\tchar_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n\t\t\t\tchar_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);\n\t\t\t\tchar_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);\n\t\t\t\tchar_array_4[3] = char_array_3[2] & 0x3f;\n\n\t\t\t\tfor (i = 0; i < 4; i++)\n\t\t\t\t\tret += base64_chars[char_array_4[i]];\n\t\t\t\ti = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (i)\n\t\t{\n\t\t\tint j;\n\t\t\tfor (j = i; j < 3; j++)\n\t\t\t\tchar_array_3[j] = '\\0';\n\n\t\t\tchar_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n\t\t\tchar_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);\n\t\t\tchar_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);\n\t\t\tchar_array_4[3] = char_array_3[2] & 0x3f;\n\n\t\t\tfor (j = 0; j < i + 1; j++)\n\t\t\t\tret += base64_chars[char_array_4[j]];\n\n\t\t\twhile (i++ < 3)\n\t\t\t\tret += '=';\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tstd::string Decode(const std::string& encoded_string)\n\t{\n\t\tsize_t in_len = encoded_string.size();\n\t\tsize_t i = 0;\n\t\tint in = 0;\n\t\tunsigned char char_array_4[4], char_array_3[3];\n\t\tstd::string ret;\n\n\t\twhile (in_len-- && encoded_string[in] != '=' && is_base64(encoded_string[in]))\n\t\t{\n\t\t\tchar_array_4[i++] = encoded_string[in];\n\t\t\tin++;\n\t\t\tif (i == 4)\n\t\t\t{\n\t\t\t\tfor (i = 0; i < 4; i++)\n\t\t\t\t\tchar_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));\n\n\t\t\t\tchar_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n\t\t\t\tchar_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n\t\t\t\tchar_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n\t\t\t\tfor (i = 0; i < 3; i++)\n\t\t\t\t\tret += char_array_3[i];\n\t\t\t\ti = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (i)\n\t\t{\n\t\t\tsize_t j;\n\t\t\tfor (j = i; j < 4; j++)\n\t\t\t\tchar_array_4[j] = 0;\n\n\t\t\tfor (j = 0; j < 4; j++)\n\t\t\t\tchar_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));\n\n\t\t\tchar_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n\t\t\tchar_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n\t\t\tchar_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n\t\t\tfor (j = 0; j < i - 1; j++)\n\t\t\t\tret += char_array_3[j];\n\t\t}\n\n\t\treturn ret;\n\t}\n};\n"
  },
  {
    "path": "KBotExt/imgui/imconfig.h",
    "content": "//-----------------------------------------------------------------------------\n// DEAR IMGUI COMPILE-TIME OPTIONS\n// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.\n// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.\n//-----------------------------------------------------------------------------\n// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)\n// B) or '#define IMGUI_USER_CONFIG \"my_imgui_config.h\"' in your project and then add directives in your own file without touching this template.\n//-----------------------------------------------------------------------------\n// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp\n// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.\n// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.\n// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.\n//-----------------------------------------------------------------------------\n\n#pragma once\n\n//---- Define assertion handler. Defaults to calling assert().\n// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.\n//#define IM_ASSERT(_EXPR)  MyAssert(_EXPR)\n//#define IM_ASSERT(_EXPR)  ((void)(_EXPR))     // Disable asserts\n\n//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows\n// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.\n// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()\n// for each static/DLL boundary you are calling from. Read \"Context and Memory Allocators\" section of imgui.cpp for more details.\n//#define IMGUI_API __declspec( dllexport )\n//#define IMGUI_API __declspec( dllimport )\n\n//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.\n#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n#define IMGUI_DISABLE_OBSOLETE_KEYIO                      // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.\n\n//---- Disable all of Dear ImGui or don't implement standard windows/tools.\n// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.\n//#define IMGUI_DISABLE                                     // Disable everything: all headers and source files will be empty.\n#define IMGUI_DISABLE_DEMO_WINDOWS                        // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.\n#define IMGUI_DISABLE_DEBUG_TOOLS                         // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).\n\n//---- Don't implement some functions to reduce linkage requirements.\n//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS   // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)\n//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS          // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)\n//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS         // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)\n//#define IMGUI_DISABLE_WIN32_FUNCTIONS                     // [Win32] Won't use and link with any Win32 function (clipboard, IME).\n//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS      // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).\n//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS            // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)\n//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS              // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.\n//#define IMGUI_DISABLE_FILE_FUNCTIONS                      // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)\n//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS              // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.\n//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS                  // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().\n//#define IMGUI_DISABLE_SSE                                 // Disable use of SSE intrinsics even if available\n\n//---- Include imgui_user.h at the end of imgui.h as a convenience\n//#define IMGUI_INCLUDE_IMGUI_USER_H\n\n//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)\n//#define IMGUI_USE_BGRA_PACKED_COLOR\n\n//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)\n#define IMGUI_USE_WCHAR32\n\n//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version\n// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.\n//#define IMGUI_STB_TRUETYPE_FILENAME   \"my_folder/stb_truetype.h\"\n//#define IMGUI_STB_RECT_PACK_FILENAME  \"my_folder/stb_rect_pack.h\"\n//#define IMGUI_STB_SPRINTF_FILENAME    \"my_folder/stb_sprintf.h\"    // only used if IMGUI_USE_STB_SPRINTF is defined.\n//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION\n//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION\n//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION                   // only disabled if IMGUI_USE_STB_SPRINTF is defined.\n\n//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)\n// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.\n//#define IMGUI_USE_STB_SPRINTF\n\n//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)\n// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).\n// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.\n#define IMGUI_ENABLE_FREETYPE\n\n//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)\n// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).\n// Only works in combination with IMGUI_ENABLE_FREETYPE.\n// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)\n//#define IMGUI_ENABLE_FREETYPE_LUNASVG\n\n//---- Use stb_truetype to build and rasterize the font atlas (default)\n// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.\n//#define IMGUI_ENABLE_STB_TRUETYPE\n\n//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.\n// This will be inlined as part of ImVec2 and ImVec4 class declarations.\n/*\n#define IM_VEC2_CLASS_EXTRA                                                     \\\n\t\tconstexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {}                   \\\n\t\toperator MyVec2() const { return MyVec2(x,y); }\n\n#define IM_VEC4_CLASS_EXTRA                                                     \\\n\t\tconstexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {}   \\\n\t\toperator MyVec4() const { return MyVec4(x,y,z,w); }\n*/\n//---- ...Or use Dear ImGui's own very basic math operators.\n//#define IMGUI_DEFINE_MATH_OPERATORS\n\n//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.\n// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).\n// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.\n// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.\n//#define ImDrawIdx unsigned int\n\n//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)\n//struct ImDrawList;\n//struct ImDrawCmd;\n//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);\n//#define ImDrawCallback MyImDrawCallback\n\n//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)\n// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)\n//#define IM_DEBUG_BREAK  IM_ASSERT(0)\n//#define IM_DEBUG_BREAK  __debugbreak()\n\n//---- Debug Tools: Enable slower asserts\n//#define IMGUI_DEBUG_PARANOID\n\n//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)\n/*\nnamespace ImGui\n{\n\tvoid MyFunction(const char* name, MyMatrix44* mtx);\n}\n*/\n"
  },
  {
    "path": "KBotExt/imgui/imgui.cpp",
    "content": "// dear imgui, v1.89.9\n// (main code and documentation)\n\n// Help:\n// - Read FAQ at http://dearimgui.com/faq\n// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.\n// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.\n// Read imgui.cpp for details, links and comments.\n\n// Resources:\n// - FAQ                   http://dearimgui.com/faq\n// - Homepage              https://github.com/ocornut/imgui\n// - Releases & changelog  https://github.com/ocornut/imgui/releases\n// - Gallery               https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!)\n// - Wiki                  https://github.com/ocornut/imgui/wiki (lots of good stuff there)\n// - Getting Started       https://github.com/ocornut/imgui/wiki/Getting-Started\n// - Glossary              https://github.com/ocornut/imgui/wiki/Glossary\n// - Issues & support      https://github.com/ocornut/imgui/issues\n// - Tests & Automation    https://github.com/ocornut/imgui_test_engine\n\n// Getting Started?\n// - Read https://github.com/ocornut/imgui/wiki/Getting-Started\n// - For first-time users having issues compiling/linking/running/loading fonts:\n//   please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.\n\n// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.\n// See LICENSE.txt for copyright and licensing details (standard MIT License).\n// This library is free but needs your support to sustain development and maintenance.\n// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts.\n// PLEASE reach out at contact AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Sponsors\n// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.\n\n// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.\n// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without\n// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't\n// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you\n// to a better solution or official support for them.\n\n/*\n\nIndex of this file:\n\nDOCUMENTATION\n\n- MISSION STATEMENT\n- CONTROLS GUIDE\n- PROGRAMMER GUIDE\n  - READ FIRST\n  - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI\n  - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE\n  - HOW A SIMPLE APPLICATION MAY LOOK LIKE\n  - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE\n- API BREAKING CHANGES (read me when you update!)\n- FREQUENTLY ASKED QUESTIONS (FAQ)\n  - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer)\n\nCODE\n(search for \"[SECTION]\" in the code to find them)\n\n// [SECTION] INCLUDES\n// [SECTION] FORWARD DECLARATIONS\n// [SECTION] CONTEXT AND MEMORY ALLOCATORS\n// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)\n// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)\n// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)\n// [SECTION] MISC HELPERS/UTILITIES (File functions)\n// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)\n// [SECTION] MISC HELPERS/UTILITIES (Color functions)\n// [SECTION] ImGuiStorage\n// [SECTION] ImGuiTextFilter\n// [SECTION] ImGuiTextBuffer, ImGuiTextIndex\n// [SECTION] ImGuiListClipper\n// [SECTION] STYLING\n// [SECTION] RENDER HELPERS\n// [SECTION] INITIALIZATION, SHUTDOWN\n// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)\n// [SECTION] INPUTS\n// [SECTION] ERROR CHECKING\n// [SECTION] LAYOUT\n// [SECTION] SCROLLING\n// [SECTION] TOOLTIPS\n// [SECTION] POPUPS\n// [SECTION] KEYBOARD/GAMEPAD NAVIGATION\n// [SECTION] DRAG AND DROP\n// [SECTION] LOGGING/CAPTURING\n// [SECTION] SETTINGS\n// [SECTION] LOCALIZATION\n// [SECTION] VIEWPORTS, PLATFORM WINDOWS\n// [SECTION] PLATFORM DEPENDENT HELPERS\n// [SECTION] METRICS/DEBUGGER WINDOW\n// [SECTION] DEBUG LOG WINDOW\n// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)\n\n*/\n\n//-----------------------------------------------------------------------------\n// DOCUMENTATION\n//-----------------------------------------------------------------------------\n\n/*\n\n MISSION STATEMENT\n =================\n\n - Easy to use to create code-driven and data-driven tools.\n - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.\n - Easy to hack and improve.\n - Minimize setup and maintenance.\n - Minimize state storage on user side.\n - Minimize state synchronization.\n - Portable, minimize dependencies, run on target (consoles, phones, etc.).\n - Efficient runtime and memory consumption.\n\n Designed primarily for developers and content-creators, not the typical end-user!\n Some of the current weaknesses (which we aim to address in the future) includes:\n\n - Doesn't look fancy.\n - Limited layout features, intricate layouts are typically crafted in code.\n\n CONTROLS GUIDE\n ==============\n\n - MOUSE CONTROLS\n   - Mouse wheel:                   Scroll vertically.\n   - SHIFT+Mouse wheel:             Scroll horizontally.\n   - Click [X]:                     Close a window, available when 'bool* p_open' is passed to ImGui::Begin().\n   - Click ^, Double-Click title:   Collapse window.\n   - Drag on corner/border:         Resize window (double-click to auto fit window to its contents).\n   - Drag on any empty space:       Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true).\n   - Left-click outside popup:      Close popup stack (right-click over underlying popup: Partially close popup stack).\n\n - TEXT EDITOR\n   - Hold SHIFT or Drag Mouse:      Select text.\n   - CTRL+Left/Right:               Word jump.\n   - CTRL+Shift+Left/Right:         Select words.\n   - CTRL+A or Double-Click:        Select All.\n   - CTRL+X, CTRL+C, CTRL+V:        Use OS clipboard.\n   - CTRL+Z, CTRL+Y:                Undo, Redo.\n   - ESCAPE:                        Revert text to its original value.\n   - On OSX, controls are automatically adjusted to match standard OSX text editing shortcuts and behaviors.\n\n - KEYBOARD CONTROLS\n   - Basic:\n\t - Tab, SHIFT+Tab               Cycle through text editable fields.\n\t - CTRL+Tab, CTRL+Shift+Tab     Cycle through windows.\n\t - CTRL+Click                   Input text into a Slider or Drag widget.\n   - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`:\n\t - Tab, SHIFT+Tab:              Cycle through every items.\n\t - Arrow keys                   Move through items using directional navigation. Tweak value.\n\t - Arrow keys + Alt, Shift      Tweak slower, tweak faster (when using arrow keys).\n\t - Enter                        Activate item (prefer text input when possible).\n\t - Space                        Activate item (prefer tweaking with arrows when possible).\n\t - Escape                       Deactivate item, leave child window, close popup.\n\t - Page Up, Page Down           Previous page, next page.\n\t - Home, End                    Scroll to top, scroll to bottom.\n\t - Alt                          Toggle between scrolling layer and menu layer.\n\t - CTRL+Tab then Ctrl+Arrows    Move window. Hold SHIFT to resize instead of moving.\n   - Output when ImGuiConfigFlags_NavEnableKeyboard set,\n\t - io.WantCaptureKeyboard flag is set when keyboard is claimed.\n\t - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.\n\t - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used).\n\n - GAMEPAD CONTROLS\n   - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.\n   - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse!\n   - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets\n   - Backend support: backend needs to:\n\t  - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.\n\t  - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.\n\t\tBackend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).\n\t  - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead!\n   - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,\n\t with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.\n\n - REMOTE INPUTS SHARING & MOUSE EMULATION\n   - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback.\n   - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app)\n\t in order to share your PC mouse/keyboard.\n   - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions.\n   - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.\n\t Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements.\n\t When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.\n\t When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.\n\t (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!)\n\t (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want\n\t to set a boolean to ignore your other external mouse positions until the external source is moved again.)\n\n PROGRAMMER GUIDE\n ================\n\n READ FIRST\n ----------\n - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)\n - Your code creates the UI every frame of your application loop, if your code doesn't run the UI is gone!\n   The UI can be highly dynamic, there are no construction or destruction steps, less superfluous\n   data retention on your side, less state duplication, less state synchronization, fewer bugs.\n - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.\n   Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version.\n - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.\n - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).\n   You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.\n - Dear ImGui is a \"single pass\" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.\n   For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,\n   where the UI code is called multiple times (\"multiple passes\") from a single entry point. There are pros and cons to both approaches.\n - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.\n - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).\n   If you get an assert, read the messages and comments around the assert.\n - This codebase aims to be highly optimized:\n   - A typical idle frame should never call malloc/free.\n   - We rely on a maximum of constant-time or O(N) algorithms. Limiting searches/scans as much as possible.\n   - We put particular energy in making sure performances are decent with typical \"Debug\" build settings as well.\n\t Which mean we tend to avoid over-relying on \"zero-cost abstraction\" as they aren't zero-cost at all.\n - This codebase aims to be both highly opinionated and highly flexible:\n   - This code works because of the things it choose to solve or not solve.\n   - C++: this is a pragmatic C-ish codebase: we don't use fancy C++ features, we don't include C++ headers,\n\t and ImGui:: is a namespace. We rarely use member functions (and when we did, I am mostly regretting it now).\n\t This is to increase compatibility, increase maintainability and facilitate use from other languages.\n   - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.\n\t See FAQ \"How can I use my own math types instead of ImVec2/ImVec4?\" for details about setting up imconfig.h for that.\n\t We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally.\n   - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction\n\t (so don't use ImVector in your code or at our own risk!).\n   - Building: We don't use nor mandate a build system for the main library.\n\t This is in an effort to ensure that it works in the real world aka with any esoteric build setup.\n\t This is also because providing a build system for the main library would be of little-value.\n\t The build problems are almost never coming from the main library but from specific backends.\n\n HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI\n ----------------------------------------------\n - Update submodule or copy/overwrite every file.\n - About imconfig.h:\n   - You may modify your copy of imconfig.h, in this case don't overwrite it.\n   - or you may locally branch to modify imconfig.h and merge/rebase latest.\n   - or you may '#define IMGUI_USER_CONFIG \"my_config_file.h\"' globally from your build system to\n\t specify a custom path for your imconfig.h file and instead not have to modify the default one.\n\n - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)\n - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over \"master\".\n - You can also use '#define IMGUI_USER_CONFIG \"my_config_file.h\" to redirect configuration to your own file.\n - Read the \"API BREAKING CHANGES\" section (below). This is where we list occasional API breaking changes.\n   If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed\n   from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will\n   likely be a comment about it. Please report any issue to the GitHub page!\n - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.\n - Try to keep your copy of Dear ImGui reasonably up to date!\n\n GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE\n ---------------------------------------------------------------\n - See https://github.com/ocornut/imgui/wiki/Getting-Started.\n - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.\n - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.\n - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.\n   It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).\n - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.\n - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.\n - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.\n   Effectively it means you can create widgets at any time in your code, regardless of considerations of being in \"update\" vs \"render\"\n   phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().\n - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code.\n - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.\n\n HOW A SIMPLE APPLICATION MAY LOOK LIKE\n --------------------------------------\n EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).\n The sub-folders in examples/ contain examples applications following this structure.\n\n\t // Application init: create a dear imgui context, setup some options, load fonts\n\t ImGui::CreateContext();\n\t ImGuiIO& io = ImGui::GetIO();\n\t // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.\n\t // TODO: Fill optional fields of the io structure later.\n\t // TODO: Load TTF/OTF fonts if you don't want to use the default font.\n\n\t // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)\n\t ImGui_ImplWin32_Init(hwnd);\n\t ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);\n\n\t // Application main loop\n\t while (true)\n\t {\n\t\t // Feed inputs to dear imgui, start new frame\n\t\t ImGui_ImplDX11_NewFrame();\n\t\t ImGui_ImplWin32_NewFrame();\n\t\t ImGui::NewFrame();\n\n\t\t // Any application code here\n\t\t ImGui::Text(\"Hello, world!\");\n\n\t\t // Render dear imgui into screen\n\t\t ImGui::Render();\n\t\t ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());\n\t\t g_pSwapChain->Present(1, 0);\n\t }\n\n\t // Shutdown\n\t ImGui_ImplDX11_Shutdown();\n\t ImGui_ImplWin32_Shutdown();\n\t ImGui::DestroyContext();\n\n EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE\n\n\t // Application init: create a dear imgui context, setup some options, load fonts\n\t ImGui::CreateContext();\n\t ImGuiIO& io = ImGui::GetIO();\n\t // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.\n\t // TODO: Fill optional fields of the io structure later.\n\t // TODO: Load TTF/OTF fonts if you don't want to use the default font.\n\n\t // Build and load the texture atlas into a texture\n\t // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)\n\t int width, height;\n\t unsigned char* pixels = nullptr;\n\t io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);\n\n\t // At this point you've got the texture data and you need to upload that to your graphic system:\n\t // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.\n\t // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.\n\t MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)\n\t io.Fonts->SetTexID((void*)texture);\n\n\t // Application main loop\n\t while (true)\n\t {\n\t\t// Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.\n\t\t// (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends)\n\t\tio.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)\n\t\tio.DisplaySize.x = 1920.0f;             // set the current display width\n\t\tio.DisplaySize.y = 1280.0f;             // set the current display height here\n\t\tio.AddMousePosEvent(mouse_x, mouse_y);  // update mouse position\n\t\tio.AddMouseButtonEvent(0, mouse_b[0]);  // update mouse button states\n\t\tio.AddMouseButtonEvent(1, mouse_b[1]);  // update mouse button states\n\n\t\t// Call NewFrame(), after this point you can use ImGui::* functions anytime\n\t\t// (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)\n\t\tImGui::NewFrame();\n\n\t\t// Most of your application code here\n\t\tImGui::Text(\"Hello, world!\");\n\t\tMyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin(\"My window\"); ImGui::Text(\"Hello, world!\"); ImGui::End();\n\t\tMyGameRender(); // may use any Dear ImGui functions as well!\n\n\t\t// Render dear imgui, swap buffers\n\t\t// (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)\n\t\tImGui::EndFrame();\n\t\tImGui::Render();\n\t\tImDrawData* draw_data = ImGui::GetDrawData();\n\t\tMyImGuiRenderFunction(draw_data);\n\t\tSwapBuffers();\n\t }\n\n\t // Shutdown\n\t ImGui::DestroyContext();\n\n To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,\n you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!\n Please read the FAQ and example applications for details about this!\n\n HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE\n ---------------------------------------------\n The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.\n\n\tvoid MyImGuiRenderFunction(ImDrawData* draw_data)\n\t{\n\t   // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled\n\t   // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering.\n\t   // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize\n\t   // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize\n\t   // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.\n\t   ImVec2 clip_off = draw_data->DisplayPos;\n\t   for (int n = 0; n < draw_data->CmdListsCount; n++)\n\t   {\n\t\t  const ImDrawList* cmd_list = draw_data->CmdLists[n];\n\t\t  const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by Dear ImGui\n\t\t  const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by Dear ImGui\n\t\t  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n\t\t  {\n\t\t\t const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n\t\t\t if (pcmd->UserCallback)\n\t\t\t {\n\t\t\t\t pcmd->UserCallback(cmd_list, pcmd);\n\t\t\t }\n\t\t\t else\n\t\t\t {\n\t\t\t\t // Project scissor/clipping rectangles into framebuffer space\n\t\t\t\t ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);\n\t\t\t\t ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);\n\t\t\t\t if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)\n\t\t\t\t\t continue;\n\n\t\t\t\t // We are using scissoring to clip some objects. All low-level graphics API should support it.\n\t\t\t\t // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches\n\t\t\t\t //   (some elements visible outside their bounds) but you can fix that once everything else works!\n\t\t\t\t // - Clipping coordinates are provided in imgui coordinates space:\n\t\t\t\t //   - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size\n\t\t\t\t //   - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values.\n\t\t\t\t //   - In the interest of supporting multi-viewport applications (see 'docking' branch on github),\n\t\t\t\t //     always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.\n\t\t\t\t // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)\n\t\t\t\t MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y);\n\n\t\t\t\t // The texture for the draw call is specified by pcmd->GetTexID().\n\t\t\t\t // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.\n\t\t\t\t MyEngineBindTexture((MyTexture*)pcmd->GetTexID());\n\n\t\t\t\t // Render 'pcmd->ElemCount/3' indexed triangles.\n\t\t\t\t // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.\n\t\t\t\t MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset);\n\t\t\t }\n\t\t  }\n\t   }\n\t}\n\n API BREAKING CHANGES\n ====================\n\n Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.\n Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.\n When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.\n You can read releases logs https://github.com/ocornut/imgui/releases for more details.\n\n - 2023/08/25 (1.89.9) - Clipper: Renamed IncludeRangeByIndices() (also called ForceDisplayRangeByIndices() before 1.89.6) to IncludeItemsByIndex(). Kept inline redirection function. Sorry!\n - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878)\n - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15).\n - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete).\n - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior.\n - 2023/06/28 (1.89.7) - overlapping items: Selectable and TreeNode don't allow overlap when active so overlapping widgets won't appear as hovered. While this fixes a common small visual issue, it also means that calling IsItemHovered() after a non-reactive elements - e.g. Text() - overlapping an active one may fail if you don't use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem). (#6610)\n - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage.\n - 2023/05/30 (1.89.6) - backends: renamed \"imgui_impl_sdlrenderer.cpp\" to \"imgui_impl_sdlrenderer2.cpp\" and \"imgui_impl_sdlrenderer.h\" to \"imgui_impl_sdlrenderer2.h\". This is in prevision for the future release of SDL3.\n - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago:\n\t\t\t\t\t\t   - ListBoxHeader()  -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference)\n\t\t\t\t\t\t   - ListBoxFooter()  -> use EndListBox()\n - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin().\n - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices().\n - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago:\n\t\t\t\t\t\t   - ImGuiSliderFlags_ClampOnInput        -> use ImGuiSliderFlags_AlwaysClamp\n\t\t\t\t\t\t   - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite\n\t\t\t\t\t\t   - ImDrawList::AddBezierCurve()         -> use ImDrawList::AddBezierCubic()\n\t\t\t\t\t\t   - ImDrawList::PathBezierCurveTo()      -> use ImDrawList::PathBezierCubicCurveTo()\n - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete).\n - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner.\n - 2023/02/15 (1.89.4) - moved the optional \"courtesy maths operators\" implementation from imgui_internal.h in imgui.h.\n\t\t\t\t\t\t Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA,\n\t\t\t\t\t\t it has been frequently requested by people to use our own. We had an opt-in define which was\n\t\t\t\t\t\t previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164)\n\t\t\t\t\t\t   - OK:     #define IMGUI_DEFINE_MATH_OPERATORS / #include \"imgui.h\" / #include \"imgui_internal.h\"\n\t\t\t\t\t\t   - Error:  #include \"imgui.h\" / #define IMGUI_DEFINE_MATH_OPERATORS / #include \"imgui_internal.h\"\n - 2023/02/07 (1.89.3) - backends: renamed \"imgui_impl_sdl.cpp\" to \"imgui_impl_sdl2.cpp\" and \"imgui_impl_sdl.h\" to \"imgui_impl_sdl2.h\". (#6146) This is in prevision for the future release of SDL3.\n - 2022/10/26 (1.89)   - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79.\n - 2022/10/12 (1.89)   - removed runtime patching of invalid \"%f\"/\"%0.f\" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.\n - 2022/09/26 (1.89)   - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete).\n\t\t\t\t\t\t   - ImGuiKey_ModCtrl  and ImGuiModFlags_Ctrl  -> ImGuiMod_Ctrl\n\t\t\t\t\t\t   - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift\n\t\t\t\t\t\t   - ImGuiKey_ModAlt   and ImGuiModFlags_Alt   -> ImGuiMod_Alt\n\t\t\t\t\t\t   - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super\n\t\t\t\t\t\t the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.\n\t\t\t\t\t\t the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions.\n\t\t\t\t\t\t exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway.\n - 2022/09/20 (1.89)   - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers.\n\t\t\t\t\t\t this will require uses of legacy backend-dependent indices to be casted, e.g.\n\t\t\t\t\t\t\t- with imgui_impl_glfw:  IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);\n\t\t\t\t\t\t\t- with imgui_impl_win32: IsKeyPressed('A')        -> IsKeyPressed((ImGuiKey)'A')\n\t\t\t\t\t\t\t- etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now!\n - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);\n - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020):\n\t\t\t\t\t\t - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.\n\t\t\t\t\t\t - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.\n\t\t\t\t\t\t - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags)\n - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries.\n\t\t\t\t\t   this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.\n\t\t\t\t\t\t - previously this would make the window content size ~200x200:\n\t\t\t\t\t\t\t  Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();\n\t\t\t\t\t\t - instead, please submit an item:\n\t\t\t\t\t\t\t  Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();\n\t\t\t\t\t\t - alternative:\n\t\t\t\t\t\t\t  Begin(...) + Dummy(ImVec2(200,200)) + End();\n\t\t\t\t\t\t - content size is now only extended when submitting an item!\n\t\t\t\t\t\t - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.\n\t\t\t\t\t\t - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.\n - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete).\n\t\t\t\t\t\t- added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.\n\t\t\t\t\t\t- old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));\n\t\t\t\t\t\t  - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.\n\t\t\t\t\t\t  - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.\n\t\t\t\t\t\t- new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));\n\t\t\t\t\t\t  - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.\n\t\t\t\t\t\t  - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.\n - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes).\n\t\t\t\t\t\t- Official backends from 1.87+                  -> no issue.\n\t\t\t\t\t\t- Official backends from 1.60 to 1.86           -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!\n\t\t\t\t\t\t- Custom backends not writing to io.NavInputs[] -> no issue.\n\t\t\t\t\t\t- Custom backends writing to io.NavInputs[]     -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!\n\t\t\t\t\t\t- TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].\n - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete).\n - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.\n - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.\n - 2022/01/20 (1.87) - inputs: reworded gamepad IO.\n\t\t\t\t\t\t- Backend writing to io.NavInputs[]            -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.\n - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).\n - 2022/01/17 (1.87) - inputs: reworked mouse IO.\n\t\t\t\t\t\t- Backend writing to io.MousePos               -> backend should call io.AddMousePosEvent()\n\t\t\t\t\t\t- Backend writing to io.MouseDown[]            -> backend should call io.AddMouseButtonEvent()\n\t\t\t\t\t\t- Backend writing to io.MouseWheel             -> backend should call io.AddMouseWheelEvent()\n\t\t\t\t\t\t- Backend writing to io.MouseHoveredViewport   -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]\n\t\t\t\t\t   note: for all calls to IO new functions, the Dear ImGui context should be bound/current.\n\t\t\t\t\t   read https://github.com/ocornut/imgui/issues/4921 for details.\n - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.\n\t\t\t\t\t\t- IsKeyPressed(MY_NATIVE_KEY_XXX)              -> use IsKeyPressed(ImGuiKey_XXX)\n\t\t\t\t\t\t- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX))      -> use IsKeyPressed(ImGuiKey_XXX)\n\t\t\t\t\t\t- Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes).\n\t\t\t\t\t\t- Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.*\n\t\t\t\t\t - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. \"io.KeyMap[ImGuiKey_A] = ImGuiKey_A\") because those values are now larger than the legacy KeyDown[] array. Will assert.\n\t\t\t\t\t - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.\n - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.\n - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.\n - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)\n\t\t\t\t\t\t- ImGui::SetNextTreeNodeOpen()        -> use ImGui::SetNextItemOpen()\n\t\t\t\t\t\t- ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x\n\t\t\t\t\t\t- ImGui::TreeAdvanceToLabelPos()      -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());\n\t\t\t\t\t\t- ImFontAtlas::CustomRect             -> use ImFontAtlasCustomRect\n\t\t\t\t\t\t- ImGuiColorEditFlags_RGB/HSV/HEX     -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex\n - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings\n - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function.\n - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.\n - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):\n\t\t\t\t\t\t- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()\n\t\t\t\t\t\t- ImFont::GlyphRangesBuilder  -> use ImFontGlyphRangesBuilder\n - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().\n\t\t\t\t\t\t- if you are using official backends from the source tree: you have nothing to do.\n\t\t\t\t\t\t- if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().\n - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.\n\t\t\t\t\t\t- ImDrawCornerFlags_TopLeft  -> use ImDrawFlags_RoundCornersTopLeft\n\t\t\t\t\t\t- ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight\n\t\t\t\t\t\t- ImDrawCornerFlags_None     -> use ImDrawFlags_RoundCornersNone etc.\n\t\t\t\t\t   flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API.\n\t\t\t\t\t   breaking: the default with rounding > 0.0f is now \"round all corners\" vs old implicit \"round no corners\":\n\t\t\t\t\t\t- rounding == 0.0f + flags == 0 --> meant no rounding  --> unchanged (common use)\n\t\t\t\t\t\t- rounding  > 0.0f + flags != 0 --> meant rounding     --> unchanged (common use)\n\t\t\t\t\t\t- rounding == 0.0f + flags != 0 --> meant no rounding  --> unchanged (unlikely use)\n\t\t\t\t\t\t- rounding  > 0.0f + flags == 0 --> meant no rounding  --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f.\n\t\t\t\t\t   this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok.\n\t\t\t\t\t   the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify \"round all corners\" and we sometimes encouraged using them as shortcuts.\n\t\t\t\t\t   legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise).\n - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018):\n\t\t\t\t\t\t- ImGui::SetScrollHere()              -> use ImGui::SetScrollHereY()\n - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.\n - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() \"bool closed\" parameter to \"ImDrawFlags flags\". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.\n - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file  with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.\n - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.\n - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).\n\t\t\t\t\t - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).\n\t\t\t\t\t - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).\n - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.\n\t\t\t\t\t - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.\n\t\t\t\t\t - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.\n - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):\n\t\t\t\t\t\t- ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().\n\t\t\t\t\t\t- ImGuiCol_ModalWindowDarkening       -> use ImGuiCol_ModalWindowDimBg\n\t\t\t\t\t\t- ImGuiInputTextCallback              -> use ImGuiTextEditCallback\n\t\t\t\t\t\t- ImGuiInputTextCallbackData          -> use ImGuiTextEditCallbackData\n - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).\n - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!\n - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.\n - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures\n - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/.\n - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018):\n\t\t\t\t\t\t- io.RenderDrawListsFn pointer        -> use ImGui::GetDrawData() value and call the render function of your backend\n\t\t\t\t\t\t- ImGui::IsAnyWindowFocused()         -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)\n\t\t\t\t\t\t- ImGui::IsAnyWindowHovered()         -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)\n\t\t\t\t\t\t- ImGuiStyleVar_Count_                -> use ImGuiStyleVar_COUNT\n\t\t\t\t\t\t- ImGuiMouseCursor_Count_             -> use ImGuiMouseCursor_COUNT\n\t\t\t\t\t  - removed redirecting functions names that were marked obsolete in 1.61 (May 2018):\n\t\t\t\t\t\t- InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = \"%.Xf\" where X is your value for decimal_precision.\n\t\t\t\t\t\t- same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter.\n - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed).\n - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).\n - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.\n - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.\n - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.\n - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!\n - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().\n\t\t\t\t\t   replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).\n\t\t\t\t\t   worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:\n\t\t\t\t\t   - if you omitted the 'power' parameter (likely!), you are not affected.\n\t\t\t\t\t   - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.\n\t\t\t\t\t   - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.\n\t\t\t\t\t   see https://github.com/ocornut/imgui/issues/3361 for all details.\n\t\t\t\t\t   kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.\n\t\t\t\t\t   for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.\n\t\t\t\t\t - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.\n - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.\n - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]\n - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.\n - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().\n - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.\n - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead.\n - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value.\n - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):\n\t\t\t\t\t   - ShowTestWindow()                    -> use ShowDemoWindow()\n\t\t\t\t\t   - IsRootWindowFocused()               -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)\n\t\t\t\t\t   - IsRootWindowOrAnyChildFocused()     -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)\n\t\t\t\t\t   - SetNextWindowContentWidth(w)        -> use SetNextWindowContentSize(ImVec2(w, 0.0f)\n\t\t\t\t\t   - GetItemsLineHeightWithSpacing()     -> use GetFrameHeightWithSpacing()\n\t\t\t\t\t   - ImGuiCol_ChildWindowBg              -> use ImGuiCol_ChildBg\n\t\t\t\t\t   - ImGuiStyleVar_ChildWindowRounding   -> use ImGuiStyleVar_ChildRounding\n\t\t\t\t\t   - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap\n\t\t\t\t\t   - IMGUI_DISABLE_TEST_WINDOWS          -> use IMGUI_DISABLE_DEMO_WINDOWS\n - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.\n - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).\n - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert.\n - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.\n - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.\n - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):\n\t\t\t\t\t   - Begin() [old 5 args version]        -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed\n\t\t\t\t\t   - IsRootWindowOrAnyChildHovered()     -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)\n\t\t\t\t\t   - AlignFirstTextHeightToWidgets()     -> use AlignTextToFramePadding()\n\t\t\t\t\t   - SetNextWindowPosCenter()            -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)\n\t\t\t\t\t   - ImFont::Glyph                       -> use ImFontGlyph\n - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse \"typematic\" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function.\n\t\t\t\t\t   if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix.\n\t\t\t\t\t   The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay).\n\t\t\t\t\t   If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.\n - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).\n - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).\n - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71.\n - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have\n\t\t\t\t\t   overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.\n\t\t\t\t\t   This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.\n\t\t\t\t\t   Please reach out if you are affected.\n - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).\n - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).\n - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.\n - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).\n - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).\n - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).\n - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!\n - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).\n - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!\n - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).\n - 2018/12/20 (1.67) - made it illegal to call Begin(\"\") with an empty string. This somehow half-worked before but had various undesirable side-effects.\n - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.\n - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.\n - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).\n - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.\n\t\t\t\t\t   If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.\n - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)\n - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.\n\t\t\t\t\t   NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.\n\t\t\t\t\t   Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.\n - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).\n - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).\n - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).\n - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.\n - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.\n - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.\n - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).\n - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan,  etc.).\n\t\t\t\t\t   old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports.\n\t\t\t\t\t   when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call.\n\t\t\t\t\t   in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.\n - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.\n - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.\n - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from \"%.0f\" to \"%d\", as we are not using integers internally any more.\n\t\t\t\t\t   If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.\n\t\t\t\t\t   To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.\n\t\t\t\t\t   If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. \"DragInt.*%f\" to help you find them.\n - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional \"int decimal_precision\" in favor of an equivalent and more flexible \"const char* format\",\n\t\t\t\t\t   consistent with other functions. Kept redirection functions (will obsolete).\n - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.\n - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch).\n - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.\n - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.\n - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.\n - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.\n - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.\n - 2018/02/07 (1.60) - reorganized context handling to be more explicit,\n\t\t\t\t\t   - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.\n\t\t\t\t\t   - removed Shutdown() function, as DestroyContext() serve this purpose.\n\t\t\t\t\t   - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.\n\t\t\t\t\t   - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.\n\t\t\t\t\t   - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.\n - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.\n - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).\n - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).\n - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.\n - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.\n - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).\n - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags\n - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.\n - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.\n - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).\n - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).\n\t\t\t\t\t - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).\n - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).\n - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).\n - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.\n - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.\n\t\t\t\t\t   Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.\n - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.\n - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.\n - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.\n - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);\n - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.\n - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.\n - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.\n\t\t\t\t\t   removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.\n\t\t\t\t\t\t IsItemHoveredRect()        --> IsItemHovered(ImGuiHoveredFlags_RectOnly)\n\t\t\t\t\t\t IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)\n\t\t\t\t\t\t IsMouseHoveringWindow()    --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]\n - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!\n - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).\n - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).\n - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).\n - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace \"io.MousePos = ImVec2(-1,-1)\" with \"io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)\".\n - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!\n\t\t\t\t\t - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).\n\t\t\t\t\t - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).\n - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.\n - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an \"ambiguous call\" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.\n - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.\n - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.\n - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).\n - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).\n - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().\n - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.\n\t\t\t\t\t - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under \"Color/Picker Widgets\", to understand the various new options.\n\t\t\t\t\t - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))'\n - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse\n - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.\n - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.\n - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().\n - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.\n - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.\n - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal.\n - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.\n\t\t\t\t\t   If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.\n\t\t\t\t\t   This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color:\n\t\t\t\t\t   ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); }\n\t\t\t\t\t   If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.\n - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().\n - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.\n - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the \"default_open = true\" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).\n - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.\n - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337).\n - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)\n - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).\n - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.\n - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.\n - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.\n - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.\n - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.\n\t\t\t\t\t   GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.\n\t\t\t\t\t   GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!\n - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize\n - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.\n - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason\n - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.\n\t\t\t\t\t   you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.\n - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.\n\t\t\t\t\t   this necessary change will break your rendering function! the fix should be very easy. sorry for that :(\n\t\t\t\t\t - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.\n\t\t\t\t\t - the signature of the io.RenderDrawListsFn handler has changed!\n\t\t\t\t\t   old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)\n\t\t\t\t\t   new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).\n\t\t\t\t\t\t parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'\n\t\t\t\t\t\t ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.\n\t\t\t\t\t\t ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.\n\t\t\t\t\t - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.\n\t\t\t\t\t - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!\n\t\t\t\t\t - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!\n - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.\n - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).\n - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.\n - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence\n - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!\n - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).\n - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).\n - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.\n - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the \"open\" state of a popup. BeginPopup() returns true if the popup is opened.\n - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).\n - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.\n - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API\n - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.\n - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.\n - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.\n - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing\n - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.\n - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)\n - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.\n - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.\n - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.\n - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior\n - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()\n - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)\n - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.\n - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.\n - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.\n\t\t\t\t\t   - old:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];\n\t\t\t\t\t   - new:  unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier);\n\t\t\t\t\t   you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation.\n - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID()\n - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)\n - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets\n - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)\n - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)\n - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility\n - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()\n - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)\n - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)\n - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()\n - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn\n - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)\n - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite\n - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes\n\n FREQUENTLY ASKED QUESTIONS (FAQ)\n ================================\n\n Read all answers online:\n   https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)\n Read all answers locally (with a text editor or ideally a Markdown viewer):\n   docs/FAQ.md\n Some answers are copied down here to facilitate searching in code.\n\n Q&A: Basics\n ===========\n\n Q: Where is the documentation?\n A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.\n\t- Run the examples/ applications and explore them.\n\t- Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide.\n\t- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.\n\t- The demo covers most features of Dear ImGui, so you can read the code and see its output.\n\t- See documentation and comments at the top of imgui.cpp + effectively imgui.h.\n\t- 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the\n\t  examples/ folder to explain how to integrate Dear ImGui with your own engine/application.\n\t- The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.\n\t- The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.\n\t- Your programming IDE is your friend, find the type or function declaration to find comments\n\t  associated with it.\n\n Q: What is this library called?\n Q: Which version should I get?\n >> This library is called \"Dear ImGui\", please don't call it \"ImGui\" :)\n >> See https://www.dearimgui.com/faq for details.\n\n Q&A: Integration\n ================\n\n Q: How to get started?\n A: Read https://github.com/ocornut/imgui/wiki/Getting-Started. Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.\n\n Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?\n A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!\n >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this.\n\n Q. How can I enable keyboard or gamepad controls?\n Q: How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)\n Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...\n Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...\n Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...\n >> See https://www.dearimgui.com/faq\n\n Q&A: Usage\n ----------\n\n Q: About the ID Stack system..\n   - Why is my widget not reacting when I click on it?\n   - How can I have widgets with an empty label?\n   - How can I have multiple widgets with the same label?\n   - How can I have multiple windows with the same label?\n Q: How can I display an image? What is ImTextureID, how does it work?\n Q: How can I use my own math types instead of ImVec2?\n Q: How can I interact with standard C++ types (such as std::string and std::vector)?\n Q: How can I display custom shapes? (using low-level ImDrawList API)\n >> See https://www.dearimgui.com/faq\n\n Q&A: Fonts, Text\n ================\n\n Q: How should I handle DPI in my application?\n Q: How can I load a different font than the default?\n Q: How can I easily use icons in my application?\n Q: How can I load multiple fonts?\n Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?\n >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md\n\n Q&A: Concerns\n =============\n\n Q: Who uses Dear ImGui?\n Q: Can you create elaborate/serious tools with Dear ImGui?\n Q: Can you reskin the look of Dear ImGui?\n Q: Why using C++ (as opposed to C)?\n >> See https://www.dearimgui.com/faq\n\n Q&A: Community\n ==============\n\n Q: How can I help?\n A: - Businesses: please reach out to \"contact AT dearimgui.com\" if you work in a place using Dear ImGui!\n\t  We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.\n\t  This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project.\n\t  Also see https://github.com/ocornut/imgui/wiki/Sponsors\n\t- Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.\n\t- If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help!\n\t- Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.\n\t  You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.\n\t  But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.\n\t- If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately).\n\n*/\n\n//-------------------------------------------------------------------------\n// [SECTION] INCLUDES\n//-------------------------------------------------------------------------\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#ifndef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS\n#endif\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_internal.h\"\n\n// System includes\n#include <stdio.h>      // vsnprintf, sscanf, printf\n#include <stdint.h>     // intptr_t\n\n// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled\n#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)\n#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS\n#endif\n\n// [Windows] OS specific includes (optional)\n#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)\n#define IMGUI_DISABLE_WIN32_FUNCTIONS\n#endif\n#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#ifndef __MINGW32__\n#include <Windows.h>        // _wfopen, OpenClipboard\n#else\n#include <windows.h>\n#endif\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions\n#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS\n#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS\n#endif\n#endif\n\n// [Apple] OS specific includes\n#if defined(__APPLE__)\n#include <TargetConditionals.h>\n#endif\n\n// Visual Studio warnings\n#ifdef _MSC_VER\n#pragma warning (disable: 4127)             // condition expression is constant\n#pragma warning (disable: 4996)             // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen\n#if defined(_MSC_VER) && _MSC_VER >= 1922   // MSVC 2019 16.2 or later\n#pragma warning (disable: 5054)             // operator '|': deprecated between enumerations of different types\n#endif\n#pragma warning (disable: 26451)            // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).\n#pragma warning (disable: 26495)            // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).\n#pragma warning (disable: 26812)            // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n#endif\n\n// Clang/GCC warnings with -Weverything\n#if defined(__clang__)\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wold-style-cast\"                 // warning: use of old-style cast                            // yes, they are more terse.\n#pragma clang diagnostic ignored \"-Wfloat-equal\"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.\n#pragma clang diagnostic ignored \"-Wformat-nonliteral\"              // warning: format string is not a string literal            // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.\n#pragma clang diagnostic ignored \"-Wexit-time-destructors\"          // warning: declaration requires an exit-time destructor     // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.\n#pragma clang diagnostic ignored \"-Wglobal-constructors\"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.\n#pragma clang diagnostic ignored \"-Wsign-conversion\"                // warning: implicit conversion changes signedness\n#pragma clang diagnostic ignored \"-Wformat-pedantic\"                // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.\n#pragma clang diagnostic ignored \"-Wint-to-void-pointer-cast\"       // warning: cast to 'void *' from smaller integer type 'int'\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.\n#pragma clang diagnostic ignored \"-Wimplicit-int-float-conversion\"  // warning: implicit conversion from 'xxx' to 'float' may lose precision\n#elif defined(__GNUC__)\n// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association.\n#pragma GCC diagnostic ignored \"-Wpragmas\"                  // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wunused-function\"          // warning: 'xxxx' defined but not used\n#pragma GCC diagnostic ignored \"-Wint-to-pointer-cast\"      // warning: cast to pointer from integer of different size\n#pragma GCC diagnostic ignored \"-Wformat\"                   // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'\n#pragma GCC diagnostic ignored \"-Wdouble-promotion\"         // warning: implicit conversion from 'float' to 'double' when passing argument to function\n#pragma GCC diagnostic ignored \"-Wconversion\"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value\n#pragma GCC diagnostic ignored \"-Wformat-nonliteral\"        // warning: format not a string literal, format string not checked\n#pragma GCC diagnostic ignored \"-Wstrict-overflow\"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"          // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#endif\n\n// Debug options\n#define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL\n#define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window\n\n// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.\nstatic const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f;    // Time before the highlight and screen dimming starts fading in\nstatic const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f;    // Time before the window list starts to appear\n\n// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)\nstatic const float WINDOWS_HOVER_PADDING = 4.0f;     // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().\nstatic const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.\nstatic const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f;    // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.\n\n// Tooltip offset\nstatic const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10);            // Multiplied by g.Style.MouseCursorScale\n\n//-------------------------------------------------------------------------\n// [SECTION] FORWARD DECLARATIONS\n//-------------------------------------------------------------------------\n\nstatic void             SetCurrentWindow(ImGuiWindow* window);\nstatic void             FindHoveredWindow();\nstatic ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);\nstatic ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);\n\nstatic void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);\n\n// Settings\nstatic void             WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);\nstatic void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);\nstatic void             WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);\nstatic void             WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);\nstatic void             WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);\n\n// Platform Dependents default implementation for IO functions\nstatic const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx);\nstatic void             SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text);\nstatic void             SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data);\n\nnamespace ImGui\n{\n\t// Navigation\n\tstatic void             NavUpdate();\n\tstatic void             NavUpdateWindowing();\n\tstatic void             NavUpdateWindowingOverlay();\n\tstatic void             NavUpdateCancelRequest();\n\tstatic void             NavUpdateCreateMoveRequest();\n\tstatic void             NavUpdateCreateTabbingRequest();\n\tstatic float            NavUpdatePageUpPageDown();\n\tstatic inline void      NavUpdateAnyRequestFlag();\n\tstatic void             NavUpdateCreateWrappingRequest();\n\tstatic void             NavEndFrame();\n\tstatic bool             NavScoreItem(ImGuiNavItemData* result);\n\tstatic void             NavApplyItemToResult(ImGuiNavItemData* result);\n\tstatic void             NavProcessItem();\n\tstatic void             NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags);\n\tstatic ImVec2           NavCalcPreferredRefPos();\n\tstatic void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);\n\tstatic ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);\n\tstatic void             NavRestoreLayer(ImGuiNavLayer layer);\n\tstatic void             NavRestoreHighlightAfterMove();\n\tstatic int              FindWindowFocusIndex(ImGuiWindow* window);\n\n\t// Error Checking and Debug Tools\n\tstatic void             ErrorCheckNewFrameSanityChecks();\n\tstatic void             ErrorCheckEndFrameSanityChecks();\n\tstatic void             UpdateDebugToolItemPicker();\n\tstatic void             UpdateDebugToolStackQueries();\n\n\t// Inputs\n\tstatic void             UpdateKeyboardInputs();\n\tstatic void             UpdateMouseInputs();\n\tstatic void             UpdateMouseWheel();\n\tstatic void             UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt);\n\n\t// Misc\n\tstatic void             UpdateSettings();\n\tstatic bool             UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);\n\tstatic void             RenderWindowOuterBorders(ImGuiWindow* window);\n\tstatic void             RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);\n\tstatic void             RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);\n\tstatic void             RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);\n\tstatic void             RenderDimmedBackgrounds();\n\n\t// Viewports\n\tstatic void             UpdateViewportsNewFrame();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] CONTEXT AND MEMORY ALLOCATORS\n//-----------------------------------------------------------------------------\n\n// DLL users:\n// - Heaps and globals are not shared across DLL boundaries!\n// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.\n// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).\n// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.\n// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).\n\n// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.\n// - ImGui::CreateContext() will automatically set this pointer if it is NULL.\n//   Change to a different context by calling ImGui::SetCurrentContext().\n// - Important: Dear ImGui functions are not thread-safe because of this pointer.\n//   If you want thread-safety to allow N threads to access N different contexts:\n//   - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h:\n//         struct ImGuiContext;\n//         extern thread_local ImGuiContext* MyImGuiTLS;\n//         #define GImGui MyImGuiTLS\n//     And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.\n//   - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586\n//   - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.\n// - DLL users: read comments above.\n#ifndef GImGui\nImGuiContext* GImGui = NULL;\n#endif\n\n// Memory Allocator functions. Use SetAllocatorFunctions() to change them.\n// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.\n// - DLL users: read comments above.\n#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS\nstatic void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }\nstatic void    FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }\n#else\nstatic void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }\nstatic void    FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }\n#endif\nstatic ImGuiMemAllocFunc    GImAllocatorAllocFunc = MallocWrapper;\nstatic ImGuiMemFreeFunc     GImAllocatorFreeFunc = FreeWrapper;\nstatic void* GImAllocatorUserData = NULL;\n\n//-----------------------------------------------------------------------------\n// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)\n//-----------------------------------------------------------------------------\n\nImGuiStyle::ImGuiStyle()\n{\n\tAlpha = 1.0f;             // Global alpha applies to everything in Dear ImGui.\n\tDisabledAlpha = 0.60f;            // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.\n\tWindowPadding = ImVec2(8, 8);      // Padding within a window\n\tWindowRounding = 0.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.\n\tWindowBorderSize = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.\n\tWindowMinSize = ImVec2(32, 32);    // Minimum window size\n\tWindowTitleAlign = ImVec2(0.0f, 0.5f);// Alignment for title bar text\n\tWindowMenuButtonPosition = ImGuiDir_Left;    // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.\n\tChildRounding = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows\n\tChildBorderSize = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.\n\tPopupRounding = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows\n\tPopupBorderSize = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.\n\tFramePadding = ImVec2(4, 3);      // Padding within a framed rectangle (used by most widgets)\n\tFrameRounding = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).\n\tFrameBorderSize = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.\n\tItemSpacing = ImVec2(8, 4);      // Horizontal and vertical spacing between widgets/lines\n\tItemInnerSpacing = ImVec2(4, 4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)\n\tCellPadding = ImVec2(4, 2);      // Padding within a table cell. CellPadding.y may be altered between different rows.\n\tTouchExtraPadding = ImVec2(0, 0);      // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!\n\tIndentSpacing = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).\n\tColumnsMinSpacing = 6.0f;             // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).\n\tScrollbarSize = 14.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar\n\tScrollbarRounding = 9.0f;             // Radius of grab corners rounding for scrollbar\n\tGrabMinSize = 12.0f;            // Minimum width/height of a grab box for slider/scrollbar\n\tGrabRounding = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.\n\tLogSliderDeadzone = 4.0f;             // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.\n\tTabRounding = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.\n\tTabBorderSize = 0.0f;             // Thickness of border around tabs.\n\tTabMinWidthForCloseButton = 0.0f;           // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.\n\tColorButtonPosition = ImGuiDir_Right;   // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.\n\tButtonTextAlign = ImVec2(0.5f, 0.5f);// Alignment of button text when button is larger than text.\n\tSelectableTextAlign = ImVec2(0.0f, 0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.\n\tSeparatorTextBorderSize = 3.0f;             // Thickkness of border in SeparatorText()\n\tSeparatorTextAlign = ImVec2(0.0f, 0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).\n\tSeparatorTextPadding = ImVec2(20.0f, 3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.\n\tDisplayWindowPadding = ImVec2(19, 19);    // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.\n\tDisplaySafeAreaPadding = ImVec2(3, 3);      // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.\n\tMouseCursorScale = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.\n\tAntiAliasedLines = true;             // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.\n\tAntiAliasedLinesUseTex = true;             // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).\n\tAntiAliasedFill = true;             // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).\n\tCurveTessellationTol = 1.25f;            // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.\n\tCircleTessellationMaxError = 0.30f;         // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.\n\n\t// Behaviors\n\tHoverStationaryDelay = 0.15f;            // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.\n\tHoverDelayShort = 0.15f;            // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.\n\tHoverDelayNormal = 0.40f;            // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). \"\n\tHoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort;    // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.\n\tHoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal;  // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.\n\n\t// Default theme\n\tImGui::StyleColorsDark(this);\n}\n\n// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.\n// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.\nvoid ImGuiStyle::ScaleAllSizes(float scale_factor)\n{\n\tWindowPadding = ImFloor(WindowPadding * scale_factor);\n\tWindowRounding = ImFloor(WindowRounding * scale_factor);\n\tWindowMinSize = ImFloor(WindowMinSize * scale_factor);\n\tChildRounding = ImFloor(ChildRounding * scale_factor);\n\tPopupRounding = ImFloor(PopupRounding * scale_factor);\n\tFramePadding = ImFloor(FramePadding * scale_factor);\n\tFrameRounding = ImFloor(FrameRounding * scale_factor);\n\tItemSpacing = ImFloor(ItemSpacing * scale_factor);\n\tItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);\n\tCellPadding = ImFloor(CellPadding * scale_factor);\n\tTouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);\n\tIndentSpacing = ImFloor(IndentSpacing * scale_factor);\n\tColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);\n\tScrollbarSize = ImFloor(ScrollbarSize * scale_factor);\n\tScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);\n\tGrabMinSize = ImFloor(GrabMinSize * scale_factor);\n\tGrabRounding = ImFloor(GrabRounding * scale_factor);\n\tLogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);\n\tTabRounding = ImFloor(TabRounding * scale_factor);\n\tTabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;\n\tSeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor);\n\tDisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);\n\tDisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);\n\tMouseCursorScale = ImFloor(MouseCursorScale * scale_factor);\n}\n\nImGuiIO::ImGuiIO()\n{\n\t// Most fields are initialized with zero\n\tmemset(this, 0, sizeof(*this));\n\tIM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT);\n\n\t// Settings\n\tConfigFlags = ImGuiConfigFlags_None;\n\tBackendFlags = ImGuiBackendFlags_None;\n\tDisplaySize = ImVec2(-1.0f, -1.0f);\n\tDeltaTime = 1.0f / 60.0f;\n\tIniSavingRate = 5.0f;\n\tIniFilename = \"imgui.ini\"; // Important: \"imgui.ini\" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).\n\tLogFilename = \"imgui_log.txt\";\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tfor (int i = 0; i < ImGuiKey_COUNT; i++)\n\t\tKeyMap[i] = -1;\n#endif\n\tUserData = NULL;\n\n\tFonts = NULL;\n\tFontGlobalScale = 1.0f;\n\tFontDefault = NULL;\n\tFontAllowUserScaling = false;\n\tDisplayFramebufferScale = ImVec2(1.0f, 1.0f);\n\n\tMouseDoubleClickTime = 0.30f;\n\tMouseDoubleClickMaxDist = 6.0f;\n\tMouseDragThreshold = 6.0f;\n\tKeyRepeatDelay = 0.275f;\n\tKeyRepeatRate = 0.050f;\n\n\t// Miscellaneous options\n\tMouseDrawCursor = false;\n#ifdef __APPLE__\n\tConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag\n#else\n\tConfigMacOSXBehaviors = false;\n#endif\n\tConfigInputTrickleEventQueue = true;\n\tConfigInputTextCursorBlink = true;\n\tConfigInputTextEnterKeepActive = false;\n\tConfigDragClickToInputText = false;\n\tConfigWindowsResizeFromEdges = true;\n\tConfigWindowsMoveFromTitleBarOnly = false;\n\tConfigMemoryCompactTimer = 60.0f;\n\tConfigDebugBeginReturnValueOnce = false;\n\tConfigDebugBeginReturnValueLoop = false;\n\n\t// Platform Functions\n\t// Note: Initialize() will setup default clipboard/ime handlers.\n\tBackendPlatformName = BackendRendererName = NULL;\n\tBackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;\n\tPlatformLocaleDecimalPoint = '.';\n\n\t// Input (NB: we already have memset zero the entire structure!)\n\tMousePos = ImVec2(-FLT_MAX, -FLT_MAX);\n\tMousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);\n\tMouseSource = ImGuiMouseSource_Mouse;\n\tfor (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;\n\tfor (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }\n\tAppAcceptingEvents = true;\n\tBackendUsingLegacyKeyArrays = (ImS8)-1;\n\tBackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong\n}\n\n// Pass in translated ASCII characters for text input.\n// - with glfw you can get those from the callback set in glfwSetCharCallback()\n// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message\n// FIXME: Should in theory be called \"AddCharacterEvent()\" to be consistent with new API\nvoid ImGuiIO::AddInputCharacter(unsigned int c)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\tif (c == 0 || !AppAcceptingEvents)\n\t\treturn;\n\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_Text;\n\te.Source = ImGuiInputSource_Keyboard;\n\te.EventId = g.InputEventsNextEventId++;\n\te.Text.Char = c;\n\tg.InputEventsQueue.push_back(e);\n}\n\n// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so\n// we should save the high surrogate.\nvoid ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)\n{\n\tif ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents)\n\t\treturn;\n\n\tif ((c & 0xFC00) == 0xD800) // High surrogate, must save\n\t{\n\t\tif (InputQueueSurrogate != 0)\n\t\t\tAddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);\n\t\tInputQueueSurrogate = c;\n\t\treturn;\n\t}\n\n\tImWchar cp = c;\n\tif (InputQueueSurrogate != 0)\n\t{\n\t\tif ((c & 0xFC00) != 0xDC00) // Invalid low surrogate\n\t\t{\n\t\t\tAddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);\n\t\t}\n\t\telse\n\t\t{\n#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF\n\t\t\tcp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar\n#else\n\t\t\tcp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);\n#endif\n\t\t}\n\n\t\tInputQueueSurrogate = 0;\n\t}\n\tAddInputCharacter((unsigned)cp);\n}\n\nvoid ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)\n{\n\tif (!AppAcceptingEvents)\n\t\treturn;\n\twhile (*utf8_chars != 0)\n\t{\n\t\tunsigned int c = 0;\n\t\tutf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);\n\t\tAddInputCharacter(c);\n\t}\n}\n\n// Clear all incoming events.\nvoid ImGuiIO::ClearEventsQueue()\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\tg.InputEventsQueue.clear();\n}\n\n// Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.\nvoid ImGuiIO::ClearInputKeys()\n{\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tmemset(KeysDown, 0, sizeof(KeysDown));\n#endif\n\tfor (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)\n\t{\n\t\tKeysData[n].Down = false;\n\t\tKeysData[n].DownDuration = -1.0f;\n\t\tKeysData[n].DownDurationPrev = -1.0f;\n\t}\n\tKeyCtrl = KeyShift = KeyAlt = KeySuper = false;\n\tKeyMods = ImGuiMod_None;\n\tMousePos = ImVec2(-FLT_MAX, -FLT_MAX);\n\tfor (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)\n\t{\n\t\tMouseDown[n] = false;\n\t\tMouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f;\n\t}\n\tMouseWheel = MouseWheelH = 0.0f;\n\tInputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().\n}\n\n// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue.\n// Current frame character buffer is now also cleared by ClearInputKeys().\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\nvoid ImGuiIO::ClearInputCharacters()\n{\n\tInputQueueCharacters.resize(0);\n}\n#endif\n\nstatic ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1)\n{\n\tImGuiContext& g = *ctx;\n\tfor (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)\n\t{\n\t\tImGuiInputEvent* e = &g.InputEventsQueue[n];\n\t\tif (e->Type != type)\n\t\t\tcontinue;\n\t\tif (type == ImGuiInputEventType_Key && e->Key.Key != arg)\n\t\t\tcontinue;\n\t\tif (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg)\n\t\t\tcontinue;\n\t\treturn e;\n\t}\n\treturn NULL;\n}\n\n// Queue a new key down/up event.\n// - ImGuiKey key:       Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)\n// - bool down:          Is the key down? use false to signify a key release.\n// - float analog_value: 0.0f..1.0f\n// IMPORTANT: THIS FUNCTION AND OTHER \"ADD\" GRABS THE CONTEXT FROM OUR INSTANCE.\n// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT.\nvoid ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)\n{\n\t//if (e->Down) { IMGUI_DEBUG_LOG_IO(\"AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\\n\", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }\n\tIM_ASSERT(Ctx != NULL);\n\tif (key == ImGuiKey_None || !AppAcceptingEvents)\n\t\treturn;\n\tImGuiContext& g = *Ctx;\n\tIM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.\n\tIM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.\n\tIM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself)\n\n\t// Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tIM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && \"Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!\");\n\tif (BackendUsingLegacyKeyArrays == -1)\n\t\tfor (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)\n\t\t\tIM_ASSERT(KeyMap[n] == -1 && \"Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!\");\n\tBackendUsingLegacyKeyArrays = 0;\n#endif\n\tif (ImGui::IsGamepadKey(key))\n\t\tBackendUsingLegacyNavInputArray = false;\n\n\t// Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)\n\tconst ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key);\n\tconst ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key);\n\tconst bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;\n\tconst float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;\n\tif (latest_key_down == down && latest_key_analog == analog_value)\n\t\treturn;\n\n\t// Add event\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_Key;\n\te.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard;\n\te.EventId = g.InputEventsNextEventId++;\n\te.Key.Key = key;\n\te.Key.Down = down;\n\te.Key.AnalogValue = analog_value;\n\tg.InputEventsQueue.push_back(e);\n}\n\nvoid ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)\n{\n\tif (!AppAcceptingEvents)\n\t\treturn;\n\tAddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);\n}\n\n// [Optional] Call after AddKeyEvent().\n// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.\n// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.\nvoid ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)\n{\n\tif (key == ImGuiKey_None)\n\t\treturn;\n\tIM_ASSERT(ImGui::IsNamedKey(key)); // >= 512\n\tIM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511\n\tIM_UNUSED(native_keycode);  // Yet unused\n\tIM_UNUSED(native_scancode); // Yet unused\n\n\t// Build native->imgui map so old user code can still call key functions with native 0..511 values.\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tconst int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode;\n\tif (!ImGui::IsLegacyKey((ImGuiKey)legacy_key))\n\t\treturn;\n\tKeyMap[legacy_key] = key;\n\tKeyMap[key] = legacy_key;\n#else\n\tIM_UNUSED(key);\n\tIM_UNUSED(native_legacy_index);\n#endif\n}\n\n// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.\nvoid ImGuiIO::SetAppAcceptingEvents(bool accepting_events)\n{\n\tAppAcceptingEvents = accepting_events;\n}\n\n// Queue a mouse move event\nvoid ImGuiIO::AddMousePosEvent(float x, float y)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\tif (!AppAcceptingEvents)\n\t\treturn;\n\n\t// Apply same flooring as UpdateMouseInputs()\n\tImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y);\n\n\t// Filter duplicate\n\tconst ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos);\n\tconst ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;\n\tif (latest_pos.x == pos.x && latest_pos.y == pos.y)\n\t\treturn;\n\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_MousePos;\n\te.Source = ImGuiInputSource_Mouse;\n\te.EventId = g.InputEventsNextEventId++;\n\te.MousePos.PosX = pos.x;\n\te.MousePos.PosY = pos.y;\n\te.MousePos.MouseSource = g.InputEventsNextMouseSource;\n\tg.InputEventsQueue.push_back(e);\n}\n\nvoid ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\tIM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);\n\tif (!AppAcceptingEvents)\n\t\treturn;\n\n\t// Filter duplicate\n\tconst ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button);\n\tconst bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];\n\tif (latest_button_down == down)\n\t\treturn;\n\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_MouseButton;\n\te.Source = ImGuiInputSource_Mouse;\n\te.EventId = g.InputEventsNextEventId++;\n\te.MouseButton.Button = mouse_button;\n\te.MouseButton.Down = down;\n\te.MouseButton.MouseSource = g.InputEventsNextMouseSource;\n\tg.InputEventsQueue.push_back(e);\n}\n\n// Queue a mouse wheel event (some mouse/API may only have a Y component)\nvoid ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\n\t// Filter duplicate (unlike most events, wheel values are relative and easy to filter)\n\tif (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))\n\t\treturn;\n\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_MouseWheel;\n\te.Source = ImGuiInputSource_Mouse;\n\te.EventId = g.InputEventsNextEventId++;\n\te.MouseWheel.WheelX = wheel_x;\n\te.MouseWheel.WheelY = wheel_y;\n\te.MouseWheel.MouseSource = g.InputEventsNextMouseSource;\n\tg.InputEventsQueue.push_back(e);\n}\n\n// This is not a real event, the data is latched in order to be stored in actual Mouse events.\n// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes.\nvoid ImGuiIO::AddMouseSourceEvent(ImGuiMouseSource source)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\tg.InputEventsNextMouseSource = source;\n}\n\nvoid ImGuiIO::AddFocusEvent(bool focused)\n{\n\tIM_ASSERT(Ctx != NULL);\n\tImGuiContext& g = *Ctx;\n\n\t// Filter duplicate\n\tconst ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus);\n\tconst bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;\n\tif (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused))\n\t\treturn;\n\n\tImGuiInputEvent e;\n\te.Type = ImGuiInputEventType_Focus;\n\te.EventId = g.InputEventsNextEventId++;\n\te.AppFocused.Focused = focused;\n\tg.InputEventsQueue.push_back(e);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)\n//-----------------------------------------------------------------------------\n\nImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)\n{\n\tIM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()\n\tImVec2 p_last = p1;\n\tImVec2 p_closest;\n\tfloat p_closest_dist2 = FLT_MAX;\n\tfloat t_step = 1.0f / (float)num_segments;\n\tfor (int i_step = 1; i_step <= num_segments; i_step++)\n\t{\n\t\tImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);\n\t\tImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);\n\t\tfloat dist2 = ImLengthSqr(p - p_line);\n\t\tif (dist2 < p_closest_dist2)\n\t\t{\n\t\t\tp_closest = p_line;\n\t\t\tp_closest_dist2 = dist2;\n\t\t}\n\t\tp_last = p_current;\n\t}\n\treturn p_closest;\n}\n\n// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp\nstatic void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)\n{\n\tfloat dx = x4 - x1;\n\tfloat dy = y4 - y1;\n\tfloat d2 = ((x2 - x4) * dy - (y2 - y4) * dx);\n\tfloat d3 = ((x3 - x4) * dy - (y3 - y4) * dx);\n\td2 = (d2 >= 0) ? d2 : -d2;\n\td3 = (d3 >= 0) ? d3 : -d3;\n\tif ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))\n\t{\n\t\tImVec2 p_current(x4, y4);\n\t\tImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);\n\t\tfloat dist2 = ImLengthSqr(p - p_line);\n\t\tif (dist2 < p_closest_dist2)\n\t\t{\n\t\t\tp_closest = p_line;\n\t\t\tp_closest_dist2 = dist2;\n\t\t}\n\t\tp_last = p_current;\n\t}\n\telse if (level < 10)\n\t{\n\t\tfloat x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;\n\t\tfloat x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;\n\t\tfloat x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;\n\t\tfloat x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;\n\t\tfloat x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;\n\t\tfloat x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;\n\t\tImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);\n\t\tImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);\n\t}\n}\n\n// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol\n// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.\nImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)\n{\n\tIM_ASSERT(tess_tol > 0.0f);\n\tImVec2 p_last = p1;\n\tImVec2 p_closest;\n\tfloat p_closest_dist2 = FLT_MAX;\n\tImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);\n\treturn p_closest;\n}\n\nImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)\n{\n\tImVec2 ap = p - a;\n\tImVec2 ab_dir = b - a;\n\tfloat dot = ap.x * ab_dir.x + ap.y * ab_dir.y;\n\tif (dot < 0.0f)\n\t\treturn a;\n\tfloat ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;\n\tif (dot > ab_len_sqr)\n\t\treturn b;\n\treturn a + ab_dir * dot / ab_len_sqr;\n}\n\nbool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)\n{\n\tbool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;\n\tbool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;\n\tbool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;\n\treturn ((b1 == b2) && (b2 == b3));\n}\n\nvoid ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)\n{\n\tImVec2 v0 = b - a;\n\tImVec2 v1 = c - a;\n\tImVec2 v2 = p - a;\n\tconst float denom = v0.x * v1.y - v1.x * v0.y;\n\tout_v = (v2.x * v1.y - v1.x * v2.y) / denom;\n\tout_w = (v0.x * v2.y - v2.x * v0.y) / denom;\n\tout_u = 1.0f - out_v - out_w;\n}\n\nImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)\n{\n\tImVec2 proj_ab = ImLineClosestPoint(a, b, p);\n\tImVec2 proj_bc = ImLineClosestPoint(b, c, p);\n\tImVec2 proj_ca = ImLineClosestPoint(c, a, p);\n\tfloat dist2_ab = ImLengthSqr(p - proj_ab);\n\tfloat dist2_bc = ImLengthSqr(p - proj_bc);\n\tfloat dist2_ca = ImLengthSqr(p - proj_ca);\n\tfloat m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));\n\tif (m == dist2_ab)\n\t\treturn proj_ab;\n\tif (m == dist2_bc)\n\t\treturn proj_bc;\n\treturn proj_ca;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)\n//-----------------------------------------------------------------------------\n\n// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.\nint ImStricmp(const char* str1, const char* str2)\n{\n\tint d;\n\twhile ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; }\n\treturn d;\n}\n\nint ImStrnicmp(const char* str1, const char* str2, size_t count)\n{\n\tint d = 0;\n\twhile (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; }\n\treturn d;\n}\n\nvoid ImStrncpy(char* dst, const char* src, size_t count)\n{\n\tif (count < 1)\n\t\treturn;\n\tif (count > 1)\n\t\tstrncpy(dst, src, count - 1);\n\tdst[count - 1] = 0;\n}\n\nchar* ImStrdup(const char* str)\n{\n\tsize_t len = strlen(str);\n\tvoid* buf = IM_ALLOC(len + 1);\n\treturn (char*)memcpy(buf, (const void*)str, len + 1);\n}\n\nchar* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)\n{\n\tsize_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;\n\tsize_t src_size = strlen(src) + 1;\n\tif (dst_buf_size < src_size)\n\t{\n\t\tIM_FREE(dst);\n\t\tdst = (char*)IM_ALLOC(src_size);\n\t\tif (p_dst_size)\n\t\t\t*p_dst_size = src_size;\n\t}\n\treturn (char*)memcpy(dst, (const void*)src, src_size);\n}\n\nconst char* ImStrchrRange(const char* str, const char* str_end, char c)\n{\n\tconst char* p = (const char*)memchr(str, (int)c, str_end - str);\n\treturn p;\n}\n\nint ImStrlenW(const ImWchar* str)\n{\n\t//return (int)wcslen((const wchar_t*)str);  // FIXME-OPT: Could use this when wchar_t are 16-bit\n\tint n = 0;\n\twhile (*str++) n++;\n\treturn n;\n}\n\n// Find end-of-line. Return pointer will point to either first \\n, either str_end.\nconst char* ImStreolRange(const char* str, const char* str_end)\n{\n\tconst char* p = (const char*)memchr(str, '\\n', str_end - str);\n\treturn p ? p : str_end;\n}\n\nconst ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line\n{\n\twhile (buf_mid_line > buf_begin && buf_mid_line[-1] != '\\n')\n\t\tbuf_mid_line--;\n\treturn buf_mid_line;\n}\n\nconst char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)\n{\n\tif (!needle_end)\n\t\tneedle_end = needle + strlen(needle);\n\n\tconst char un0 = (char)ImToUpper(*needle);\n\twhile ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))\n\t{\n\t\tif (ImToUpper(*haystack) == un0)\n\t\t{\n\t\t\tconst char* b = needle + 1;\n\t\t\tfor (const char* a = haystack + 1; b < needle_end; a++, b++)\n\t\t\t\tif (ImToUpper(*a) != ImToUpper(*b))\n\t\t\t\t\tbreak;\n\t\t\tif (b == needle_end)\n\t\t\t\treturn haystack;\n\t\t}\n\t\thaystack++;\n\t}\n\treturn NULL;\n}\n\n// Trim str by offsetting contents when there's leading data + writing a \\0 at the trailing position. We use this in situation where the cost is negligible.\nvoid ImStrTrimBlanks(char* buf)\n{\n\tchar* p = buf;\n\twhile (p[0] == ' ' || p[0] == '\\t')     // Leading blanks\n\t\tp++;\n\tchar* p_start = p;\n\twhile (*p != 0)                         // Find end of string\n\t\tp++;\n\twhile (p > p_start && (p[-1] == ' ' || p[-1] == '\\t'))  // Trailing blanks\n\t\tp--;\n\tif (p_start != buf)                     // Copy memory if we had leading blanks\n\t\tmemmove(buf, p_start, p - p_start);\n\tbuf[p - p_start] = 0;                   // Zero terminate\n}\n\nconst char* ImStrSkipBlank(const char* str)\n{\n\twhile (str[0] == ' ' || str[0] == '\\t')\n\t\tstr++;\n\treturn str;\n}\n\n// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).\n// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.\n// B) When buf==NULL vsnprintf() will return the output size.\n#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS\n\n// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)\n// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS\n// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are\n// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)\n#ifdef IMGUI_USE_STB_SPRINTF\n#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION\n#define STB_SPRINTF_IMPLEMENTATION\n#endif\n#ifdef IMGUI_STB_SPRINTF_FILENAME\n#include IMGUI_STB_SPRINTF_FILENAME\n#else\n#include \"stb_sprintf.h\"\n#endif\n#endif // #ifdef IMGUI_USE_STB_SPRINTF\n\n#if defined(_MSC_VER) && !defined(vsnprintf)\n#define vsnprintf _vsnprintf\n#endif\n\nint ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n#ifdef IMGUI_USE_STB_SPRINTF\n\tint w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);\n#else\n\tint w = vsnprintf(buf, buf_size, fmt, args);\n#endif\n\tva_end(args);\n\tif (buf == NULL)\n\t\treturn w;\n\tif (w == -1 || w >= (int)buf_size)\n\t\tw = (int)buf_size - 1;\n\tbuf[w] = 0;\n\treturn w;\n}\n\nint ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)\n{\n#ifdef IMGUI_USE_STB_SPRINTF\n\tint w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);\n#else\n\tint w = vsnprintf(buf, buf_size, fmt, args);\n#endif\n\tif (buf == NULL)\n\t\treturn w;\n\tif (w == -1 || w >= (int)buf_size)\n\t\tw = (int)buf_size - 1;\n\tbuf[w] = 0;\n\treturn w;\n}\n#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS\n\nvoid ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...)\n{\n\tImGuiContext& g = *GImGui;\n\tva_list args;\n\tva_start(args, fmt);\n\tif (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)\n\t{\n\t\tconst char* buf = va_arg(args, const char*); // Skip formatting when using \"%s\"\n\t\t*out_buf = buf;\n\t\tif (out_buf_end) { *out_buf_end = buf + strlen(buf); }\n\t}\n\telse\n\t{\n\t\tint buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);\n\t\t*out_buf = g.TempBuffer.Data;\n\t\tif (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }\n\t}\n\tva_end(args);\n}\n\nvoid ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)\n{\n\tImGuiContext& g = *GImGui;\n\tif (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)\n\t{\n\t\tconst char* buf = va_arg(args, const char*); // Skip formatting when using \"%s\"\n\t\t*out_buf = buf;\n\t\tif (out_buf_end) { *out_buf_end = buf + strlen(buf); }\n\t}\n\telse\n\t{\n\t\tint buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);\n\t\t*out_buf = g.TempBuffer.Data;\n\t\tif (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }\n\t}\n}\n\n// CRC32 needs a 1KB lookup table (not cache friendly)\n// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:\n// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.\nstatic const ImU32 GCrc32LookupTable[256] =\n{\n\t0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,\n\t0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,\n\t0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,\n\t0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,\n\t0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,\n\t0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,\n\t0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,\n\t0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,\n\t0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,\n\t0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,\n\t0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,\n\t0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,\n\t0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,\n\t0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,\n\t0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,\n\t0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,\n};\n\n// Known size hash\n// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.\n// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.\nImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)\n{\n\tImU32 crc = ~seed;\n\tconst unsigned char* data = (const unsigned char*)data_p;\n\tconst ImU32* crc32_lut = GCrc32LookupTable;\n\twhile (data_size-- != 0)\n\t\tcrc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];\n\treturn ~crc;\n}\n\n// Zero-terminated string hash, with support for ### to reset back to seed value\n// We support a syntax of \"label###id\" where only \"###id\" is included in the hash, and only \"label\" gets displayed.\n// Because this syntax is rarely used we are optimizing for the common case.\n// - If we reach ### in the string we discard the hash so far and reset to the seed.\n// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)\n// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.\nImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)\n{\n\tseed = ~seed;\n\tImU32 crc = seed;\n\tconst unsigned char* data = (const unsigned char*)data_p;\n\tconst ImU32* crc32_lut = GCrc32LookupTable;\n\tif (data_size != 0)\n\t{\n\t\twhile (data_size-- != 0)\n\t\t{\n\t\t\tunsigned char c = *data++;\n\t\t\tif (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')\n\t\t\t\tcrc = seed;\n\t\t\tcrc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];\n\t\t}\n\t}\n\telse\n\t{\n\t\twhile (unsigned char c = *data++)\n\t\t{\n\t\t\tif (c == '#' && data[0] == '#' && data[1] == '#')\n\t\t\t\tcrc = seed;\n\t\t\tcrc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];\n\t\t}\n\t}\n\treturn ~crc;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] MISC HELPERS/UTILITIES (File functions)\n//-----------------------------------------------------------------------------\n\n// Default file functions\n#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS\n\nImFileHandle ImFileOpen(const char* filename, const char* mode)\n{\n#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)\n\t// We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.\n\t// Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!\n\tconst int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);\n\tconst int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);\n\tImVector<wchar_t> buf;\n\tbuf.resize(filename_wsize + mode_wsize);\n\t::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);\n\t::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);\n\treturn ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);\n#else\n\treturn fopen(filename, mode);\n#endif\n}\n\n// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.\nbool    ImFileClose(ImFileHandle f) { return fclose(f) == 0; }\nImU64   ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }\nImU64   ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }\nImU64   ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }\n#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS\n\n// Helper: Load file content into memory\n// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()\n// This can't really be used with \"rt\" because fseek size won't match read size.\nvoid* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)\n{\n\tIM_ASSERT(filename && mode);\n\tif (out_file_size)\n\t\t*out_file_size = 0;\n\n\tImFileHandle f;\n\tif ((f = ImFileOpen(filename, mode)) == NULL)\n\t\treturn NULL;\n\n\tsize_t file_size = (size_t)ImFileGetSize(f);\n\tif (file_size == (size_t)-1)\n\t{\n\t\tImFileClose(f);\n\t\treturn NULL;\n\t}\n\n\tvoid* file_data = IM_ALLOC(file_size + padding_bytes);\n\tif (file_data == NULL)\n\t{\n\t\tImFileClose(f);\n\t\treturn NULL;\n\t}\n\tif (ImFileRead(file_data, 1, file_size, f) != file_size)\n\t{\n\t\tImFileClose(f);\n\t\tIM_FREE(file_data);\n\t\treturn NULL;\n\t}\n\tif (padding_bytes > 0)\n\t\tmemset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);\n\n\tImFileClose(f);\n\tif (out_file_size)\n\t\t*out_file_size = file_size;\n\n\treturn file_data;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)\n//-----------------------------------------------------------------------------\n\nIM_MSVC_RUNTIME_CHECKS_OFF\n\n// Convert UTF-8 to 32-bit character, process single character input.\n// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).\n// We handle UTF-8 decoding error by skipping forward.\nint ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)\n{\n\tstatic const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 };\n\tstatic const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };\n\tstatic const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };\n\tstatic const int shiftc[] = { 0, 18, 12, 6, 0 };\n\tstatic const int shifte[] = { 0, 6, 4, 2, 0 };\n\tint len = lengths[*(const unsigned char*)in_text >> 3];\n\tint wanted = len + (len ? 0 : 1);\n\n\tif (in_text_end == NULL)\n\t\tin_text_end = in_text + wanted; // Max length, nulls will be taken into account.\n\n\t// Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here,\n\t// so it is fast even with excessive branching.\n\tunsigned char s[4];\n\ts[0] = in_text + 0 < in_text_end ? in_text[0] : 0;\n\ts[1] = in_text + 1 < in_text_end ? in_text[1] : 0;\n\ts[2] = in_text + 2 < in_text_end ? in_text[2] : 0;\n\ts[3] = in_text + 3 < in_text_end ? in_text[3] : 0;\n\n\t// Assume a four-byte character and load four bytes. Unused bits are shifted out.\n\t*out_char = (uint32_t)(s[0] & masks[len]) << 18;\n\t*out_char |= (uint32_t)(s[1] & 0x3f) << 12;\n\t*out_char |= (uint32_t)(s[2] & 0x3f) << 6;\n\t*out_char |= (uint32_t)(s[3] & 0x3f) << 0;\n\t*out_char >>= shiftc[len];\n\n\t// Accumulate the various error conditions.\n\tint e = 0;\n\te = (*out_char < mins[len]) << 6; // non-canonical encoding\n\te |= ((*out_char >> 11) == 0x1b) << 7;  // surrogate half?\n\te |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8;  // out of range?\n\te |= (s[1] & 0xc0) >> 2;\n\te |= (s[2] & 0xc0) >> 4;\n\te |= (s[3]) >> 6;\n\te ^= 0x2a; // top two bits of each tail byte correct?\n\te >>= shifte[len];\n\n\tif (e)\n\t{\n\t\t// No bytes are consumed when *in_text == 0 || in_text == in_text_end.\n\t\t// One byte is consumed in case of invalid first byte of in_text.\n\t\t// All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes.\n\t\t// Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s.\n\t\twanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);\n\t\t*out_char = IM_UNICODE_CODEPOINT_INVALID;\n\t}\n\n\treturn wanted;\n}\n\nint ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)\n{\n\tImWchar* buf_out = buf;\n\tImWchar* buf_end = buf + buf_size;\n\twhile (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)\n\t{\n\t\tunsigned int c;\n\t\tin_text += ImTextCharFromUtf8(&c, in_text, in_text_end);\n\t\t*buf_out++ = (ImWchar)c;\n\t}\n\t*buf_out = 0;\n\tif (in_text_remaining)\n\t\t*in_text_remaining = in_text;\n\treturn (int)(buf_out - buf);\n}\n\nint ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)\n{\n\tint char_count = 0;\n\twhile ((!in_text_end || in_text < in_text_end) && *in_text)\n\t{\n\t\tunsigned int c;\n\t\tin_text += ImTextCharFromUtf8(&c, in_text, in_text_end);\n\t\tchar_count++;\n\t}\n\treturn char_count;\n}\n\n// Based on stb_to_utf8() from github.com/nothings/stb/\nstatic inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)\n{\n\tif (c < 0x80)\n\t{\n\t\tbuf[0] = (char)c;\n\t\treturn 1;\n\t}\n\tif (c < 0x800)\n\t{\n\t\tif (buf_size < 2) return 0;\n\t\tbuf[0] = (char)(0xc0 + (c >> 6));\n\t\tbuf[1] = (char)(0x80 + (c & 0x3f));\n\t\treturn 2;\n\t}\n\tif (c < 0x10000)\n\t{\n\t\tif (buf_size < 3) return 0;\n\t\tbuf[0] = (char)(0xe0 + (c >> 12));\n\t\tbuf[1] = (char)(0x80 + ((c >> 6) & 0x3f));\n\t\tbuf[2] = (char)(0x80 + ((c) & 0x3f));\n\t\treturn 3;\n\t}\n\tif (c <= 0x10FFFF)\n\t{\n\t\tif (buf_size < 4) return 0;\n\t\tbuf[0] = (char)(0xf0 + (c >> 18));\n\t\tbuf[1] = (char)(0x80 + ((c >> 12) & 0x3f));\n\t\tbuf[2] = (char)(0x80 + ((c >> 6) & 0x3f));\n\t\tbuf[3] = (char)(0x80 + ((c) & 0x3f));\n\t\treturn 4;\n\t}\n\t// Invalid code point, the max unicode is 0x10FFFF\n\treturn 0;\n}\n\nconst char* ImTextCharToUtf8(char out_buf[5], unsigned int c)\n{\n\tint count = ImTextCharToUtf8_inline(out_buf, 5, c);\n\tout_buf[count] = 0;\n\treturn out_buf;\n}\n\n// Not optimal but we very rarely use this function.\nint ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)\n{\n\tunsigned int unused = 0;\n\treturn ImTextCharFromUtf8(&unused, in_text, in_text_end);\n}\n\nstatic inline int ImTextCountUtf8BytesFromChar(unsigned int c)\n{\n\tif (c < 0x80) return 1;\n\tif (c < 0x800) return 2;\n\tif (c < 0x10000) return 3;\n\tif (c <= 0x10FFFF) return 4;\n\treturn 3;\n}\n\nint ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)\n{\n\tchar* buf_p = out_buf;\n\tconst char* buf_end = out_buf + out_buf_size;\n\twhile (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)\n\t{\n\t\tunsigned int c = (unsigned int)(*in_text++);\n\t\tif (c < 0x80)\n\t\t\t*buf_p++ = (char)c;\n\t\telse\n\t\t\tbuf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);\n\t}\n\t*buf_p = 0;\n\treturn (int)(buf_p - out_buf);\n}\n\nint ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)\n{\n\tint bytes_count = 0;\n\twhile ((!in_text_end || in_text < in_text_end) && *in_text)\n\t{\n\t\tunsigned int c = (unsigned int)(*in_text++);\n\t\tif (c < 0x80)\n\t\t\tbytes_count++;\n\t\telse\n\t\t\tbytes_count += ImTextCountUtf8BytesFromChar(c);\n\t}\n\treturn bytes_count;\n}\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n//-----------------------------------------------------------------------------\n// [SECTION] MISC HELPERS/UTILITIES (Color functions)\n// Note: The Convert functions are early design which are not consistent with other API.\n//-----------------------------------------------------------------------------\n\nIMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)\n{\n\tfloat t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;\n\tint r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);\n\tint g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);\n\tint b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);\n\treturn IM_COL32(r, g, b, 0xFF);\n}\n\nImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)\n{\n\tfloat s = 1.0f / 255.0f;\n\treturn ImVec4(\n\t\t((in >> IM_COL32_R_SHIFT) & 0xFF) * s,\n\t\t((in >> IM_COL32_G_SHIFT) & 0xFF) * s,\n\t\t((in >> IM_COL32_B_SHIFT) & 0xFF) * s,\n\t\t((in >> IM_COL32_A_SHIFT) & 0xFF) * s);\n}\n\nImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)\n{\n\tImU32 out;\n\tout = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;\n\tout |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;\n\tout |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;\n\tout |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;\n\treturn out;\n}\n\n// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592\n// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv\nvoid ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)\n{\n\tfloat K = 0.f;\n\tif (g < b)\n\t{\n\t\tImSwap(g, b);\n\t\tK = -1.f;\n\t}\n\tif (r < g)\n\t{\n\t\tImSwap(r, g);\n\t\tK = -2.f / 6.f - K;\n\t}\n\n\tconst float chroma = r - (g < b ? g : b);\n\tout_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));\n\tout_s = chroma / (r + 1e-20f);\n\tout_v = r;\n}\n\n// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593\n// also http://en.wikipedia.org/wiki/HSL_and_HSV\nvoid ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)\n{\n\tif (s == 0.0f)\n\t{\n\t\t// gray\n\t\tout_r = out_g = out_b = v;\n\t\treturn;\n\t}\n\n\th = ImFmod(h, 1.0f) / (60.0f / 360.0f);\n\tint   i = (int)h;\n\tfloat f = h - (float)i;\n\tfloat p = v * (1.0f - s);\n\tfloat q = v * (1.0f - s * f);\n\tfloat t = v * (1.0f - s * (1.0f - f));\n\n\tswitch (i)\n\t{\n\tcase 0: out_r = v; out_g = t; out_b = p; break;\n\tcase 1: out_r = q; out_g = v; out_b = p; break;\n\tcase 2: out_r = p; out_g = v; out_b = t; break;\n\tcase 3: out_r = p; out_g = q; out_b = v; break;\n\tcase 4: out_r = t; out_g = p; out_b = v; break;\n\tcase 5: default: out_r = v; out_g = p; out_b = q; break;\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiStorage\n// Helper: Key->value storage\n//-----------------------------------------------------------------------------\n\n// std::lower_bound but without the bullshit\nstatic ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)\n{\n\tImGuiStorage::ImGuiStoragePair* first = data.Data;\n\tImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;\n\tsize_t count = (size_t)(last - first);\n\twhile (count > 0)\n\t{\n\t\tsize_t count2 = count >> 1;\n\t\tImGuiStorage::ImGuiStoragePair* mid = first + count2;\n\t\tif (mid->key < key)\n\t\t{\n\t\t\tfirst = ++mid;\n\t\t\tcount -= count2 + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcount = count2;\n\t\t}\n\t}\n\treturn first;\n}\n\n// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.\nvoid ImGuiStorage::BuildSortByKey()\n{\n\tstruct StaticFunc\n\t{\n\t\tstatic int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)\n\t\t{\n\t\t\t// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.\n\t\t\tif (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;\n\t\t\tif (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;\n\t\t\treturn 0;\n\t\t}\n\t};\n\tImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);\n}\n\nint ImGuiStorage::GetInt(ImGuiID key, int default_val) const\n{\n\tImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);\n\tif (it == Data.end() || it->key != key)\n\t\treturn default_val;\n\treturn it->val_i;\n}\n\nbool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const\n{\n\treturn GetInt(key, default_val ? 1 : 0) != 0;\n}\n\nfloat ImGuiStorage::GetFloat(ImGuiID key, float default_val) const\n{\n\tImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);\n\tif (it == Data.end() || it->key != key)\n\t\treturn default_val;\n\treturn it->val_f;\n}\n\nvoid* ImGuiStorage::GetVoidPtr(ImGuiID key) const\n{\n\tImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);\n\tif (it == Data.end() || it->key != key)\n\t\treturn NULL;\n\treturn it->val_p;\n}\n\n// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.\nint* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t\tit = Data.insert(it, ImGuiStoragePair(key, default_val));\n\treturn &it->val_i;\n}\n\nbool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)\n{\n\treturn (bool*)GetIntRef(key, default_val ? 1 : 0);\n}\n\nfloat* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t\tit = Data.insert(it, ImGuiStoragePair(key, default_val));\n\treturn &it->val_f;\n}\n\nvoid** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t\tit = Data.insert(it, ImGuiStoragePair(key, default_val));\n\treturn &it->val_p;\n}\n\n// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)\nvoid ImGuiStorage::SetInt(ImGuiID key, int val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t{\n\t\tData.insert(it, ImGuiStoragePair(key, val));\n\t\treturn;\n\t}\n\tit->val_i = val;\n}\n\nvoid ImGuiStorage::SetBool(ImGuiID key, bool val)\n{\n\tSetInt(key, val ? 1 : 0);\n}\n\nvoid ImGuiStorage::SetFloat(ImGuiID key, float val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t{\n\t\tData.insert(it, ImGuiStoragePair(key, val));\n\t\treturn;\n\t}\n\tit->val_f = val;\n}\n\nvoid ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)\n{\n\tImGuiStoragePair* it = LowerBound(Data, key);\n\tif (it == Data.end() || it->key != key)\n\t{\n\t\tData.insert(it, ImGuiStoragePair(key, val));\n\t\treturn;\n\t}\n\tit->val_p = val;\n}\n\nvoid ImGuiStorage::SetAllInt(int v)\n{\n\tfor (int i = 0; i < Data.Size; i++)\n\t\tData[i].val_i = v;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiTextFilter\n//-----------------------------------------------------------------------------\n\n// Helper: Parse and apply text filters. In format \"aaaaa[,bbbb][,ccccc]\"\nImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077\n{\n\tInputBuf[0] = 0;\n\tCountGrep = 0;\n\tif (default_filter)\n\t{\n\t\tImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));\n\t\tBuild();\n\t}\n}\n\nbool ImGuiTextFilter::Draw(const char* label, float width)\n{\n\tif (width != 0.0f)\n\t\tImGui::SetNextItemWidth(width);\n\tbool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));\n\tif (value_changed)\n\t\tBuild();\n\treturn value_changed;\n}\n\nvoid ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const\n{\n\tout->resize(0);\n\tconst char* wb = b;\n\tconst char* we = wb;\n\twhile (we < e)\n\t{\n\t\tif (*we == separator)\n\t\t{\n\t\t\tout->push_back(ImGuiTextRange(wb, we));\n\t\t\twb = we + 1;\n\t\t}\n\t\twe++;\n\t}\n\tif (wb != we)\n\t\tout->push_back(ImGuiTextRange(wb, we));\n}\n\nvoid ImGuiTextFilter::Build()\n{\n\tFilters.resize(0);\n\tImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));\n\tinput_range.split(',', &Filters);\n\n\tCountGrep = 0;\n\tfor (ImGuiTextRange& f : Filters)\n\t{\n\t\twhile (f.b < f.e && ImCharIsBlankA(f.b[0]))\n\t\t\tf.b++;\n\t\twhile (f.e > f.b && ImCharIsBlankA(f.e[-1]))\n\t\t\tf.e--;\n\t\tif (f.empty())\n\t\t\tcontinue;\n\t\tif (f.b[0] != '-')\n\t\t\tCountGrep += 1;\n\t}\n}\n\nbool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const\n{\n\tif (Filters.empty())\n\t\treturn true;\n\n\tif (text == NULL)\n\t\ttext = \"\";\n\n\tfor (const ImGuiTextRange& f : Filters)\n\t{\n\t\tif (f.empty())\n\t\t\tcontinue;\n\t\tif (f.b[0] == '-')\n\t\t{\n\t\t\t// Subtract\n\t\t\tif (ImStristr(text, text_end, f.b + 1, f.e) != NULL)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Grep\n\t\t\tif (ImStristr(text, text_end, f.b, f.e) != NULL)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Implicit * grep\n\tif (CountGrep == 0)\n\t\treturn true;\n\n\treturn false;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiTextBuffer, ImGuiTextIndex\n//-----------------------------------------------------------------------------\n\n// On some platform vsnprintf() takes va_list by reference and modifies it.\n// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.\n#ifndef va_copy\n#if defined(__GNUC__) || defined(__clang__)\n#define va_copy(dest, src) __builtin_va_copy(dest, src)\n#else\n#define va_copy(dest, src) (dest = src)\n#endif\n#endif\n\nchar ImGuiTextBuffer::EmptyString[1] = { 0 };\n\nvoid ImGuiTextBuffer::append(const char* str, const char* str_end)\n{\n\tint len = str_end ? (int)(str_end - str) : (int)strlen(str);\n\n\t// Add zero-terminator the first time\n\tconst int write_off = (Buf.Size != 0) ? Buf.Size : 1;\n\tconst int needed_sz = write_off + len;\n\tif (write_off + len >= Buf.Capacity)\n\t{\n\t\tint new_capacity = Buf.Capacity * 2;\n\t\tBuf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);\n\t}\n\n\tBuf.resize(needed_sz);\n\tmemcpy(&Buf[write_off - 1], str, (size_t)len);\n\tBuf[write_off - 1 + len] = 0;\n}\n\nvoid ImGuiTextBuffer::appendf(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tappendfv(fmt, args);\n\tva_end(args);\n}\n\n// Helper: Text buffer for logging/accumulating text\nvoid ImGuiTextBuffer::appendfv(const char* fmt, va_list args)\n{\n\tva_list args_copy;\n\tva_copy(args_copy, args);\n\n\tint len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.\n\tif (len <= 0)\n\t{\n\t\tva_end(args_copy);\n\t\treturn;\n\t}\n\n\t// Add zero-terminator the first time\n\tconst int write_off = (Buf.Size != 0) ? Buf.Size : 1;\n\tconst int needed_sz = write_off + len;\n\tif (write_off + len >= Buf.Capacity)\n\t{\n\t\tint new_capacity = Buf.Capacity * 2;\n\t\tBuf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);\n\t}\n\n\tBuf.resize(needed_sz);\n\tImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);\n\tva_end(args_copy);\n}\n\nvoid ImGuiTextIndex::append(const char* base, int old_size, int new_size)\n{\n\tIM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);\n\tif (old_size == new_size)\n\t\treturn;\n\tif (EndOffset == 0 || base[EndOffset - 1] == '\\n')\n\t\tLineOffsets.push_back(EndOffset);\n\tconst char* base_end = base + new_size;\n\tfor (const char* p = base + old_size; (p = (const char*)memchr(p, '\\n', base_end - p)) != 0; )\n\t\tif (++p < base_end) // Don't push a trailing offset on last \\n\n\t\t\tLineOffsets.push_back((int)(intptr_t)(p - base));\n\tEndOffset = ImMax(EndOffset, new_size);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiListClipper\n// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed\n// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)\n//-----------------------------------------------------------------------------\n\n// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell.\n// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous.\nstatic bool GetSkipItemForListClipping()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);\n}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n// Legacy helper to calculate coarse clipping of large list of evenly sized items.\n// This legacy API is not ideal because it assumes we will return a single contiguous rectangle.\n// Prefer using ImGuiListClipper which can returns non-contiguous ranges.\nvoid ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (g.LogEnabled)\n\t{\n\t\t// If logging is active, do not perform any clipping\n\t\t*out_items_display_start = 0;\n\t\t*out_items_display_end = items_count;\n\t\treturn;\n\t}\n\tif (GetSkipItemForListClipping())\n\t{\n\t\t*out_items_display_start = *out_items_display_end = 0;\n\t\treturn;\n\t}\n\n\t// We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect\n\t// We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly.\n\tImRect rect = window->ClipRect;\n\tif (g.NavMoveScoringItems)\n\t\trect.Add(g.NavScoringNoClipRect);\n\tif (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)\n\t\trect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel\n\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tint start = (int)((rect.Min.y - pos.y) / items_height);\n\tint end = (int)((rect.Max.y - pos.y) / items_height);\n\n\t// When performing a navigation request, ensure we have one item extra in the direction we are moving to\n\t// FIXME: Verify this works with tabbing\n\tconst bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);\n\tif (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up)\n\t\tstart--;\n\tif (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down)\n\t\tend++;\n\n\tstart = ImClamp(start, 0, items_count);\n\tend = ImClamp(end + 1, start, items_count);\n\t*out_items_display_start = start;\n\t*out_items_display_end = end;\n}\n#endif\n\nstatic void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0)\n{\n\tif (ranges.Size - offset <= 1)\n\t\treturn;\n\n\t// Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries)\n\tfor (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end)\n\t\tfor (int i = offset; i < sort_end + offset; ++i)\n\t\t\tif (ranges[i].Min > ranges[i + 1].Min)\n\t\t\t\tImSwap(ranges[i], ranges[i + 1]);\n\n\t// Now fuse ranges together as much as possible.\n\tfor (int i = 1 + offset; i < ranges.Size; i++)\n\t{\n\t\tIM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert);\n\t\tif (ranges[i - 1].Max < ranges[i].Min)\n\t\t\tcontinue;\n\t\tranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min);\n\t\tranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max);\n\t\tranges.erase(ranges.Data + i);\n\t\ti--;\n\t}\n}\n\nstatic void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)\n{\n\t// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.\n\t// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.\n\t// The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek?\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tfloat off_y = pos_y - window->DC.CursorPos.y;\n\twindow->DC.CursorPos.y = pos_y;\n\twindow->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y);\n\twindow->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;  // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.\n\twindow->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y);      // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.\n\tif (ImGuiOldColumns* columns = window->DC.CurrentColumns)\n\t\tcolumns->LineMinY = window->DC.CursorPos.y;                         // Setting this so that cell Y position are set properly\n\tif (ImGuiTable* table = g.CurrentTable)\n\t{\n\t\tif (table->IsInsideRow)\n\t\t\tImGui::TableEndRow(table);\n\t\ttable->RowPosY2 = window->DC.CursorPos.y;\n\t\tconst int row_increase = (int)((off_y / line_height) + 0.5f);\n\t\t//table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()\n\t\ttable->RowBgColorCounter += row_increase;\n\t}\n}\n\nstatic void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)\n{\n\t// StartPosY starts from ItemsFrozen hence the subtraction\n\t// Perform the add and multiply with double to allow seeking through larger ranges\n\tImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;\n\tfloat pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight);\n\tImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);\n}\n\nImGuiListClipper::ImGuiListClipper()\n{\n\tmemset(this, 0, sizeof(*this));\n}\n\nImGuiListClipper::~ImGuiListClipper()\n{\n\tEnd();\n}\n\nvoid ImGuiListClipper::Begin(int items_count, float items_height)\n{\n\tif (Ctx == NULL)\n\t\tCtx = ImGui::GetCurrentContext();\n\n\tImGuiContext& g = *Ctx;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: Begin(%d,%.2f) in '%s'\\n\", items_count, items_height, window->Name);\n\n\tif (ImGuiTable* table = g.CurrentTable)\n\t\tif (table->IsInsideRow)\n\t\t\tImGui::TableEndRow(table);\n\n\tStartPosY = window->DC.CursorPos.y;\n\tItemsHeight = items_height;\n\tItemsCount = items_count;\n\tDisplayStart = -1;\n\tDisplayEnd = 0;\n\n\t// Acquire temporary buffer\n\tif (++g.ClipperTempDataStacked > g.ClipperTempData.Size)\n\t\tg.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData());\n\tImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];\n\tdata->Reset(this);\n\tdata->LossynessOffset = window->DC.CursorStartPosLossyness.y;\n\tTempData = data;\n}\n\nvoid ImGuiListClipper::End()\n{\n\tif (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)\n\t{\n\t\t// In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.\n\t\tImGuiContext& g = *Ctx;\n\t\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: End() in '%s'\\n\", g.CurrentWindow->Name);\n\t\tif (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)\n\t\t\tImGuiListClipper_SeekCursorForItem(this, ItemsCount);\n\n\t\t// Restore temporary buffer and fix back pointers which may be invalidated when nesting\n\t\tIM_ASSERT(data->ListClipper == this);\n\t\tdata->StepNo = data->Ranges.Size;\n\t\tif (--g.ClipperTempDataStacked > 0)\n\t\t{\n\t\t\tdata = &g.ClipperTempData[g.ClipperTempDataStacked - 1];\n\t\t\tdata->ListClipper->TempData = data;\n\t\t}\n\t\tTempData = NULL;\n\t}\n\tItemsCount = -1;\n}\n\nvoid ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)\n{\n\tImGuiListClipperData* data = (ImGuiListClipperData*)TempData;\n\tIM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.\n\tIM_ASSERT(item_begin <= item_end);\n\tif (item_begin < item_end)\n\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end));\n}\n\nstatic bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)\n{\n\tImGuiContext& g = *clipper->Ctx;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;\n\tIM_ASSERT(data != NULL && \"Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?\");\n\n\tImGuiTable* table = g.CurrentTable;\n\tif (table && table->IsInsideRow)\n\t\tImGui::TableEndRow(table);\n\n\t// No items\n\tif (clipper->ItemsCount == 0 || GetSkipItemForListClipping())\n\t\treturn false;\n\n\t// While we are in frozen row state, keep displaying items one by one, unclipped\n\t// FIXME: Could be stored as a table-agnostic state.\n\tif (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows)\n\t{\n\t\tclipper->DisplayStart = data->ItemsFrozen;\n\t\tclipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount);\n\t\tif (clipper->DisplayStart < clipper->DisplayEnd)\n\t\t\tdata->ItemsFrozen++;\n\t\treturn true;\n\t}\n\n\t// Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)\n\tbool calc_clipping = false;\n\tif (data->StepNo == 0)\n\t{\n\t\tclipper->StartPosY = window->DC.CursorPos.y;\n\t\tif (clipper->ItemsHeight <= 0.0f)\n\t\t{\n\t\t\t// Submit the first item (or range) so we can measure its height (generally the first range is 0..1)\n\t\t\tdata->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1));\n\t\t\tclipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);\n\t\t\tclipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount);\n\t\t\tdata->StepNo = 1;\n\t\t\treturn true;\n\t\t}\n\t\tcalc_clipping = true;   // If on the first step with known item height, calculate clipping.\n\t}\n\n\t// Step 1: Let the clipper infer height from first range\n\tif (clipper->ItemsHeight <= 0.0f)\n\t{\n\t\tIM_ASSERT(data->StepNo == 1);\n\t\tif (table)\n\t\t\tIM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);\n\n\t\tclipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart);\n\t\tbool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);\n\t\tif (affected_by_floating_point_precision)\n\t\t\tclipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.\n\n\t\tIM_ASSERT(clipper->ItemsHeight > 0.0f && \"Unable to calculate item height! First item hasn't moved the cursor vertically!\");\n\t\tcalc_clipping = true;   // If item height had to be calculated, calculate clipping afterwards.\n\t}\n\n\t// Step 0 or 1: Calculate the actual ranges of visible elements.\n\tconst int already_submitted = clipper->DisplayEnd;\n\tif (calc_clipping)\n\t{\n\t\tif (g.LogEnabled)\n\t\t{\n\t\t\t// If logging is active, do not perform any clipping\n\t\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Add range selected to be included for navigation\n\t\t\tconst bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);\n\t\t\tif (is_nav_request)\n\t\t\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0));\n\t\t\tif (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1)\n\t\t\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount));\n\n\t\t\t// Add focused/active item\n\t\t\tImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]);\n\t\t\tif (g.NavId != 0 && window->NavLastIds[0] == g.NavId)\n\t\t\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));\n\n\t\t\t// Add visible range\n\t\t\tconst int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;\n\t\t\tconst int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;\n\t\t\tdata->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max));\n\t\t}\n\n\t\t// Convert position ranges to item index ranges\n\t\t// - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.\n\t\t// - Due to how Selectable extra padding they tend to be \"unaligned\" with exact unit in the item list,\n\t\t//   which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.\n\t\tfor (ImGuiListClipperRange& range : data->Ranges)\n\t\t\tif (range.PosToIndexConvert)\n\t\t\t{\n\t\t\t\tint m1 = (int)(((double)range.Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);\n\t\t\t\tint m2 = (int)((((double)range.Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);\n\t\t\t\trange.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);\n\t\t\t\trange.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper->ItemsCount);\n\t\t\t\trange.PosToIndexConvert = false;\n\t\t\t}\n\t\tImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);\n\t}\n\n\t// Step 0+ (if item height is given in advance) or 1+: Display the next range in line.\n\twhile (data->StepNo < data->Ranges.Size)\n\t{\n\t\tclipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);\n\t\tclipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);\n\t\tif (clipper->DisplayStart > already_submitted) //-V1051\n\t\t\tImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);\n\t\tdata->StepNo++;\n\t\tif (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)\n\t\t\tcontinue;\n\t\treturn true;\n\t}\n\n\t// After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),\n\t// Advance the cursor to the end of the list and then returns 'false' to end the loop.\n\tif (clipper->ItemsCount < INT_MAX)\n\t\tImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount);\n\n\treturn false;\n}\n\nbool ImGuiListClipper::Step()\n{\n\tImGuiContext& g = *Ctx;\n\tbool need_items_height = (ItemsHeight <= 0.0f);\n\tbool ret = ImGuiListClipper_StepInternal(this);\n\tif (ret && (DisplayStart == DisplayEnd))\n\t\tret = false;\n\tif (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false)\n\t\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: Step(): inside frozen table row.\\n\");\n\tif (need_items_height && ItemsHeight > 0.0f)\n\t\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: Step(): computed ItemsHeight: %.2f.\\n\", ItemsHeight);\n\tif (ret)\n\t{\n\t\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: Step(): display %d to %d.\\n\", DisplayStart, DisplayEnd);\n\t}\n\telse\n\t{\n\t\tIMGUI_DEBUG_LOG_CLIPPER(\"Clipper: Step(): End.\\n\");\n\t\tEnd();\n\t}\n\treturn ret;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] STYLING\n//-----------------------------------------------------------------------------\n\nImGuiStyle& ImGui::GetStyle()\n{\n\tIM_ASSERT(GImGui != NULL && \"No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?\");\n\treturn GImGui->Style;\n}\n\nImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)\n{\n\tImGuiStyle& style = GImGui->Style;\n\tImVec4 c = style.Colors[idx];\n\tc.w *= style.Alpha * alpha_mul;\n\treturn ColorConvertFloat4ToU32(c);\n}\n\nImU32 ImGui::GetColorU32(const ImVec4& col)\n{\n\tImGuiStyle& style = GImGui->Style;\n\tImVec4 c = col;\n\tc.w *= style.Alpha;\n\treturn ColorConvertFloat4ToU32(c);\n}\n\nconst ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)\n{\n\tImGuiStyle& style = GImGui->Style;\n\treturn style.Colors[idx];\n}\n\nImU32 ImGui::GetColorU32(ImU32 col)\n{\n\tImGuiStyle& style = GImGui->Style;\n\tif (style.Alpha >= 1.0f)\n\t\treturn col;\n\tImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;\n\ta = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.\n\treturn (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);\n}\n\n// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32\nvoid ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiColorMod backup;\n\tbackup.Col = idx;\n\tbackup.BackupValue = g.Style.Colors[idx];\n\tg.ColorStack.push_back(backup);\n\tg.Style.Colors[idx] = ColorConvertU32ToFloat4(col);\n}\n\nvoid ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiColorMod backup;\n\tbackup.Col = idx;\n\tbackup.BackupValue = g.Style.Colors[idx];\n\tg.ColorStack.push_back(backup);\n\tg.Style.Colors[idx] = col;\n}\n\nvoid ImGui::PopStyleColor(int count)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.ColorStack.Size < count)\n\t{\n\t\tIM_ASSERT_USER_ERROR(g.ColorStack.Size > count, \"Calling PopStyleColor() too many times: stack underflow.\");\n\t\tcount = g.ColorStack.Size;\n\t}\n\twhile (count > 0)\n\t{\n\t\tImGuiColorMod& backup = g.ColorStack.back();\n\t\tg.Style.Colors[backup.Col] = backup.BackupValue;\n\t\tg.ColorStack.pop_back();\n\t\tcount--;\n\t}\n}\n\nstatic const ImGuiDataVarInfo GStyleVarInfo[] =\n{\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) },       // ImGuiStyleVar_DisabledAlpha\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) },         // ImGuiStyleVar_CellPadding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign\n\t{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) },     // ImGuiStyleVar_SeparatorTextAlign\n\t{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) },   // ImGuiStyleVar_SeparatorTextPadding\n};\n\nconst ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx)\n{\n\tIM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);\n\tIM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);\n\treturn &GStyleVarInfo[idx];\n}\n\nvoid ImGui::PushStyleVar(ImGuiStyleVar idx, float val)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);\n\tif (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)\n\t{\n\t\tfloat* pvar = (float*)var_info->GetVarPtr(&g.Style);\n\t\tg.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));\n\t\t*pvar = val;\n\t\treturn;\n\t}\n\tIM_ASSERT_USER_ERROR(0, \"Called PushStyleVar() variant with wrong type!\");\n}\n\nvoid ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);\n\tif (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)\n\t{\n\t\tImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);\n\t\tg.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));\n\t\t*pvar = val;\n\t\treturn;\n\t}\n\tIM_ASSERT_USER_ERROR(0, \"Called PushStyleVar() variant with wrong type!\");\n}\n\nvoid ImGui::PopStyleVar(int count)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.StyleVarStack.Size < count)\n\t{\n\t\tIM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, \"Calling PopStyleVar() too many times: stack underflow.\");\n\t\tcount = g.StyleVarStack.Size;\n\t}\n\twhile (count > 0)\n\t{\n\t\t// We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.\n\t\tImGuiStyleMod& backup = g.StyleVarStack.back();\n\t\tconst ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx);\n\t\tvoid* data = info->GetVarPtr(&g.Style);\n\t\tif (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }\n\t\telse if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }\n\t\tg.StyleVarStack.pop_back();\n\t\tcount--;\n\t}\n}\n\nconst char* ImGui::GetStyleColorName(ImGuiCol idx)\n{\n\t// Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\\1: return \"\\1\";\n\tswitch (idx)\n\t{\n\tcase ImGuiCol_Text: return \"Text\";\n\tcase ImGuiCol_TextDisabled: return \"TextDisabled\";\n\tcase ImGuiCol_WindowBg: return \"WindowBg\";\n\tcase ImGuiCol_ChildBg: return \"ChildBg\";\n\tcase ImGuiCol_PopupBg: return \"PopupBg\";\n\tcase ImGuiCol_Border: return \"Border\";\n\tcase ImGuiCol_BorderShadow: return \"BorderShadow\";\n\tcase ImGuiCol_FrameBg: return \"FrameBg\";\n\tcase ImGuiCol_FrameBgHovered: return \"FrameBgHovered\";\n\tcase ImGuiCol_FrameBgActive: return \"FrameBgActive\";\n\tcase ImGuiCol_TitleBg: return \"TitleBg\";\n\tcase ImGuiCol_TitleBgActive: return \"TitleBgActive\";\n\tcase ImGuiCol_TitleBgCollapsed: return \"TitleBgCollapsed\";\n\tcase ImGuiCol_MenuBarBg: return \"MenuBarBg\";\n\tcase ImGuiCol_ScrollbarBg: return \"ScrollbarBg\";\n\tcase ImGuiCol_ScrollbarGrab: return \"ScrollbarGrab\";\n\tcase ImGuiCol_ScrollbarGrabHovered: return \"ScrollbarGrabHovered\";\n\tcase ImGuiCol_ScrollbarGrabActive: return \"ScrollbarGrabActive\";\n\tcase ImGuiCol_CheckMark: return \"CheckMark\";\n\tcase ImGuiCol_SliderGrab: return \"SliderGrab\";\n\tcase ImGuiCol_SliderGrabActive: return \"SliderGrabActive\";\n\tcase ImGuiCol_Button: return \"Button\";\n\tcase ImGuiCol_ButtonHovered: return \"ButtonHovered\";\n\tcase ImGuiCol_ButtonActive: return \"ButtonActive\";\n\tcase ImGuiCol_Header: return \"Header\";\n\tcase ImGuiCol_HeaderHovered: return \"HeaderHovered\";\n\tcase ImGuiCol_HeaderActive: return \"HeaderActive\";\n\tcase ImGuiCol_Separator: return \"Separator\";\n\tcase ImGuiCol_SeparatorHovered: return \"SeparatorHovered\";\n\tcase ImGuiCol_SeparatorActive: return \"SeparatorActive\";\n\tcase ImGuiCol_ResizeGrip: return \"ResizeGrip\";\n\tcase ImGuiCol_ResizeGripHovered: return \"ResizeGripHovered\";\n\tcase ImGuiCol_ResizeGripActive: return \"ResizeGripActive\";\n\tcase ImGuiCol_Tab: return \"Tab\";\n\tcase ImGuiCol_TabHovered: return \"TabHovered\";\n\tcase ImGuiCol_TabActive: return \"TabActive\";\n\tcase ImGuiCol_TabUnfocused: return \"TabUnfocused\";\n\tcase ImGuiCol_TabUnfocusedActive: return \"TabUnfocusedActive\";\n\tcase ImGuiCol_PlotLines: return \"PlotLines\";\n\tcase ImGuiCol_PlotLinesHovered: return \"PlotLinesHovered\";\n\tcase ImGuiCol_PlotHistogram: return \"PlotHistogram\";\n\tcase ImGuiCol_PlotHistogramHovered: return \"PlotHistogramHovered\";\n\tcase ImGuiCol_TableHeaderBg: return \"TableHeaderBg\";\n\tcase ImGuiCol_TableBorderStrong: return \"TableBorderStrong\";\n\tcase ImGuiCol_TableBorderLight: return \"TableBorderLight\";\n\tcase ImGuiCol_TableRowBg: return \"TableRowBg\";\n\tcase ImGuiCol_TableRowBgAlt: return \"TableRowBgAlt\";\n\tcase ImGuiCol_TextSelectedBg: return \"TextSelectedBg\";\n\tcase ImGuiCol_DragDropTarget: return \"DragDropTarget\";\n\tcase ImGuiCol_NavHighlight: return \"NavHighlight\";\n\tcase ImGuiCol_NavWindowingHighlight: return \"NavWindowingHighlight\";\n\tcase ImGuiCol_NavWindowingDimBg: return \"NavWindowingDimBg\";\n\tcase ImGuiCol_ModalWindowDimBg: return \"ModalWindowDimBg\";\n\t}\n\tIM_ASSERT(0);\n\treturn \"Unknown\";\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] RENDER HELPERS\n// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,\n// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.\n// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.\n//-----------------------------------------------------------------------------\n\nconst char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)\n{\n\tconst char* text_display_end = text;\n\tif (!text_end)\n\t\ttext_end = (const char*)-1;\n\n\twhile (text_display_end < text_end && *text_display_end != '\\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))\n\t\ttext_display_end++;\n\treturn text_display_end;\n}\n\n// Internal ImGui functions to render text\n// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()\nvoid ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// Hide anything after a '##' string\n\tconst char* text_display_end;\n\tif (hide_text_after_hash)\n\t{\n\t\ttext_display_end = FindRenderedTextEnd(text, text_end);\n\t}\n\telse\n\t{\n\t\tif (!text_end)\n\t\t\ttext_end = text + strlen(text); // FIXME-OPT\n\t\ttext_display_end = text_end;\n\t}\n\n\tif (text != text_display_end)\n\t{\n\t\twindow->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);\n\t\tif (g.LogEnabled)\n\t\t\tLogRenderedText(&pos, text, text_display_end);\n\t}\n}\n\nvoid ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tif (!text_end)\n\t\ttext_end = text + strlen(text); // FIXME-OPT\n\n\tif (text != text_end)\n\t{\n\t\twindow->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);\n\t\tif (g.LogEnabled)\n\t\t\tLogRenderedText(&pos, text, text_end);\n\t}\n}\n\n// Default clip_rect uses (pos_min,pos_max)\n// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)\n// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList.\n// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take\n// better advantage of the render function taking size into account for coarse clipping.\nvoid ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)\n{\n\t// Perform CPU side clipping for single clipped element to avoid using scissor state\n\tImVec2 pos = pos_min;\n\tconst ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);\n\n\tconst ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;\n\tconst ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;\n\tbool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);\n\tif (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min\n\t\tneed_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);\n\n\t// Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.\n\tif (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);\n\tif (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);\n\n\t// Render\n\tif (need_clipping)\n\t{\n\t\tImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);\n\t\tdraw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);\n\t}\n\telse\n\t{\n\t\tdraw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);\n\t}\n}\n\nvoid ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)\n{\n\t// Hide anything after a '##' string\n\tconst char* text_display_end = FindRenderedTextEnd(text, text_end);\n\tconst int text_len = (int)(text_display_end - text);\n\tif (text_len == 0)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tRenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);\n\tif (g.LogEnabled)\n\t\tLogRenderedText(&pos_min, text, text_display_end);\n}\n\n// Another overly complex function until we reorganize everything into a nice all-in-one helper.\n// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.\n// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.\nvoid ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)\n{\n\tImGuiContext& g = *GImGui;\n\tif (text_end_full == NULL)\n\t\ttext_end_full = FindRenderedTextEnd(text);\n\tconst ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);\n\n\t//draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));\n\t//draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));\n\t//draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));\n\t// FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.\n\tif (text_size.x > pos_max.x - pos_min.x)\n\t{\n\t\t// Hello wo...\n\t\t// |       |   |\n\t\t// min   max   ellipsis_max\n\t\t//          <-> this is generally some padding value\n\n\t\tconst ImFont* font = draw_list->_Data->Font;\n\t\tconst float font_size = draw_list->_Data->FontSize;\n\t\tconst float font_scale = font_size / font->FontSize;\n\t\tconst char* text_end_ellipsis = NULL;\n\t\tconst float ellipsis_width = font->EllipsisWidth * font_scale;\n\n\t\t// We can now claim the space between pos_max.x and ellipsis_max.x\n\t\tconst float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);\n\t\tfloat text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;\n\t\tif (text == text_end_ellipsis && text_end_ellipsis < text_end_full)\n\t\t{\n\t\t\t// Always display at least 1 character if there's no room for character + ellipsis\n\t\t\ttext_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);\n\t\t\ttext_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;\n\t\t}\n\t\twhile (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))\n\t\t{\n\t\t\t// Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)\n\t\t\ttext_end_ellipsis--;\n\t\t\ttext_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte\n\t\t}\n\n\t\t// Render text, render ellipsis\n\t\tRenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));\n\t\tImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));\n\t\tif (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x)\n\t\t\tfor (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale)\n\t\t\t\tfont->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar);\n\t}\n\telse\n\t{\n\t\tRenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));\n\t}\n\n\tif (g.LogEnabled)\n\t\tLogRenderedText(&pos_min, text, text_end_full);\n}\n\n// Render a rectangle shaped with optional rounding and borders\nvoid ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\twindow->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);\n\tconst float border_size = g.Style.FrameBorderSize;\n\tif (border && border_size > 0.0f)\n\t{\n\t\twindow->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);\n\t\twindow->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);\n\t}\n}\n\nvoid ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tconst float border_size = g.Style.FrameBorderSize;\n\tif (border_size > 0.0f)\n\t{\n\t\twindow->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);\n\t\twindow->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);\n\t}\n}\n\nvoid ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (id != g.NavId)\n\t\treturn;\n\tif (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))\n\t\treturn;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->DC.NavHideHighlightOneFrame)\n\t\treturn;\n\n\tfloat rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;\n\tImRect display_rect = bb;\n\tdisplay_rect.ClipWith(window->ClipRect);\n\tif (flags & ImGuiNavHighlightFlags_TypeDefault)\n\t{\n\t\tconst float THICKNESS = 2.0f;\n\t\tconst float DISTANCE = 3.0f + THICKNESS * 0.5f;\n\t\tdisplay_rect.Expand(ImVec2(DISTANCE, DISTANCE));\n\t\tbool fully_visible = window->ClipRect.Contains(display_rect);\n\t\tif (!fully_visible)\n\t\t\twindow->DrawList->PushClipRect(display_rect.Min, display_rect.Max);\n\t\twindow->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS);\n\t\tif (!fully_visible)\n\t\t\twindow->DrawList->PopClipRect();\n\t}\n\tif (flags & ImGuiNavHighlightFlags_TypeThin)\n\t{\n\t\twindow->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f);\n\t}\n}\n\nvoid ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);\n\tImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t{\n\t\t// We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.\n\t\tImVec2 offset, size, uv[4];\n\t\tif (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))\n\t\t\tcontinue;\n\t\tconst ImVec2 pos = base_pos - offset;\n\t\tconst float scale = base_scale;\n\t\tif (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))\n\t\t\tcontinue;\n\t\tImDrawList* draw_list = GetForegroundDrawList(viewport);\n\t\tImTextureID tex_id = font_atlas->TexID;\n\t\tdraw_list->PushTextureID(tex_id);\n\t\tdraw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);\n\t\tdraw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);\n\t\tdraw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);\n\t\tdraw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);\n\t\tdraw_list->PopTextureID();\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] INITIALIZATION, SHUTDOWN\n//-----------------------------------------------------------------------------\n\n// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself\n// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module\nImGuiContext* ImGui::GetCurrentContext()\n{\n\treturn GImGui;\n}\n\nvoid ImGui::SetCurrentContext(ImGuiContext* ctx)\n{\n#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC\n\tIMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.\n#else\n\tGImGui = ctx;\n#endif\n}\n\nvoid ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data)\n{\n\tGImAllocatorAllocFunc = alloc_func;\n\tGImAllocatorFreeFunc = free_func;\n\tGImAllocatorUserData = user_data;\n}\n\n// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space)\nvoid ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data)\n{\n\t*p_alloc_func = GImAllocatorAllocFunc;\n\t*p_free_func = GImAllocatorFreeFunc;\n\t*p_user_data = GImAllocatorUserData;\n}\n\nImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)\n{\n\tImGuiContext* prev_ctx = GetCurrentContext();\n\tImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);\n\tSetCurrentContext(ctx);\n\tInitialize();\n\tif (prev_ctx != NULL)\n\t\tSetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one.\n\treturn ctx;\n}\n\nvoid ImGui::DestroyContext(ImGuiContext* ctx)\n{\n\tImGuiContext* prev_ctx = GetCurrentContext();\n\tif (ctx == NULL) //-V1051\n\t\tctx = prev_ctx;\n\tSetCurrentContext(ctx);\n\tShutdown();\n\tSetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL);\n\tIM_DELETE(ctx);\n}\n\n// IMPORTANT: ###xxx suffixes must be same in ALL languages\nstatic const ImGuiLocEntry GLocalizationEntriesEnUS[] =\n{\n\t{ ImGuiLocKey_VersionStr,           \"Dear ImGui \" IMGUI_VERSION \" (\" IM_STRINGIFY(IMGUI_VERSION_NUM) \")\" },\n\t{ ImGuiLocKey_TableSizeOne,         \"Size column to fit###SizeOne\"          },\n\t{ ImGuiLocKey_TableSizeAllFit,      \"Size all columns to fit###SizeAll\"     },\n\t{ ImGuiLocKey_TableSizeAllDefault,  \"Size all columns to default###SizeAll\" },\n\t{ ImGuiLocKey_TableResetOrder,      \"Reset order###ResetOrder\"              },\n\t{ ImGuiLocKey_WindowingMainMenuBar, \"(Main menu bar)\"                       },\n\t{ ImGuiLocKey_WindowingPopup,       \"(Popup)\"                               },\n\t{ ImGuiLocKey_WindowingUntitled,    \"(Untitled)\"                            },\n};\n\nvoid ImGui::Initialize()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(!g.Initialized && !g.SettingsLoaded);\n\n\t// Add .ini handle for ImGuiWindow and ImGuiTable types\n\t{\n\t\tImGuiSettingsHandler ini_handler;\n\t\tini_handler.TypeName = \"Window\";\n\t\tini_handler.TypeHash = ImHashStr(\"Window\");\n\t\tini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;\n\t\tini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;\n\t\tini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;\n\t\tini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;\n\t\tini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;\n\t\tAddSettingsHandler(&ini_handler);\n\t}\n\tTableSettingsAddSettingsHandler();\n\n\t// Setup default localization table\n\tLocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS));\n\n\t// Setup default platform clipboard/IME handlers.\n\tg.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;    // Platform dependent default implementations\n\tg.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;\n\tg.IO.ClipboardUserData = (void*)&g;                          // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function)\n\tg.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl;\n\n\t// Create default viewport\n\tImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();\n\tg.Viewports.push_back(viewport);\n\tg.TempBuffer.resize(1024 * 3 + 1, 0);\n\n#ifdef IMGUI_HAS_DOCK\n#endif\n\n\tg.Initialized = true;\n}\n\n// This function is merely here to free heap allocations.\nvoid ImGui::Shutdown()\n{\n\t// The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)\n\tImGuiContext& g = *GImGui;\n\tif (g.IO.Fonts && g.FontAtlasOwnedByContext)\n\t{\n\t\tg.IO.Fonts->Locked = false;\n\t\tIM_DELETE(g.IO.Fonts);\n\t}\n\tg.IO.Fonts = NULL;\n\tg.DrawListSharedData.TempBuffer.clear();\n\n\t// Cleanup of other data are conditional on actually having initialized Dear ImGui.\n\tif (!g.Initialized)\n\t\treturn;\n\n\t// Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)\n\tif (g.SettingsLoaded && g.IO.IniFilename != NULL)\n\t\tSaveIniSettingsToDisk(g.IO.IniFilename);\n\n\tCallContextHooks(&g, ImGuiContextHookType_Shutdown);\n\n\t// Clear everything else\n\tg.Windows.clear_delete();\n\tg.WindowsFocusOrder.clear();\n\tg.WindowsTempSortBuffer.clear();\n\tg.CurrentWindow = NULL;\n\tg.CurrentWindowStack.clear();\n\tg.WindowsById.Clear();\n\tg.NavWindow = NULL;\n\tg.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;\n\tg.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;\n\tg.MovingWindow = NULL;\n\n\tg.KeysRoutingTable.Clear();\n\n\tg.ColorStack.clear();\n\tg.StyleVarStack.clear();\n\tg.FontStack.clear();\n\tg.OpenPopupStack.clear();\n\tg.BeginPopupStack.clear();\n\tg.NavTreeNodeStack.clear();\n\n\tg.Viewports.clear_delete();\n\n\tg.TabBars.Clear();\n\tg.CurrentTabBarStack.clear();\n\tg.ShrinkWidthBuffer.clear();\n\n\tg.ClipperTempData.clear_destruct();\n\n\tg.Tables.Clear();\n\tg.TablesTempData.clear_destruct();\n\tg.DrawChannelsTempMergeBuffer.clear();\n\n\tg.ClipboardHandlerData.clear();\n\tg.MenusIdSubmittedThisFrame.clear();\n\tg.InputTextState.ClearFreeMemory();\n\tg.InputTextDeactivatedState.ClearFreeMemory();\n\n\tg.SettingsWindows.clear();\n\tg.SettingsHandlers.clear();\n\n\tif (g.LogFile)\n\t{\n#ifndef IMGUI_DISABLE_TTY_FUNCTIONS\n\t\tif (g.LogFile != stdout)\n#endif\n\t\t\tImFileClose(g.LogFile);\n\t\tg.LogFile = NULL;\n\t}\n\tg.LogBuffer.clear();\n\tg.DebugLogBuf.clear();\n\tg.DebugLogIndex.clear();\n\n\tg.Initialized = false;\n}\n\n// No specific ordering/dependency support, will see as needed\nImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook)\n{\n\tImGuiContext& g = *ctx;\n\tIM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);\n\tg.Hooks.push_back(*hook);\n\tg.Hooks.back().HookId = ++g.HookIdNext;\n\treturn g.HookIdNext;\n}\n\n// Deferred removal, avoiding issue with changing vector while iterating it\nvoid ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)\n{\n\tImGuiContext& g = *ctx;\n\tIM_ASSERT(hook_id != 0);\n\tfor (ImGuiContextHook& hook : g.Hooks)\n\t\tif (hook.HookId == hook_id)\n\t\t\thook.Type = ImGuiContextHookType_PendingRemoval_;\n}\n\n// Call context hooks (used by e.g. test engine)\n// We assume a small number of hooks so all stored in same array\nvoid ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)\n{\n\tImGuiContext& g = *ctx;\n\tfor (ImGuiContextHook& hook : g.Hooks)\n\t\tif (hook.Type == hook_type)\n\t\t\thook.Callback(&g, &hook);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)\n//-----------------------------------------------------------------------------\n\n// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods\nImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)\n{\n\tmemset(this, 0, sizeof(*this));\n\tCtx = ctx;\n\tName = ImStrdup(name);\n\tNameBufLen = (int)strlen(name) + 1;\n\tID = ImHashStr(name);\n\tIDStack.push_back(ID);\n\tMoveId = GetID(\"#MOVE\");\n\tScrollTarget = ImVec2(FLT_MAX, FLT_MAX);\n\tScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);\n\tAutoFitFramesX = AutoFitFramesY = -1;\n\tAutoPosLastDirection = ImGuiDir_None;\n\tSetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = 0;\n\tSetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);\n\tLastFrameActive = -1;\n\tLastTimeActive = -1.0f;\n\tFontWindowScale = 1.0f;\n\tSettingsOffset = -1;\n\tDrawList = &DrawListInst;\n\tDrawList->_Data = &Ctx->DrawListSharedData;\n\tDrawList->_OwnerName = Name;\n\tNavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX);\n}\n\nImGuiWindow::~ImGuiWindow()\n{\n\tIM_ASSERT(DrawList == &DrawListInst);\n\tIM_DELETE(Name);\n\tColumnsStorage.clear_destruct();\n}\n\nImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)\n{\n\tImGuiID seed = IDStack.back();\n\tImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);\n\tImGuiContext& g = *Ctx;\n\tif (g.DebugHookIdInfo == id)\n\t\tImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);\n\treturn id;\n}\n\nImGuiID ImGuiWindow::GetID(const void* ptr)\n{\n\tImGuiID seed = IDStack.back();\n\tImGuiID id = ImHashData(&ptr, sizeof(void*), seed);\n\tImGuiContext& g = *Ctx;\n\tif (g.DebugHookIdInfo == id)\n\t\tImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);\n\treturn id;\n}\n\nImGuiID ImGuiWindow::GetID(int n)\n{\n\tImGuiID seed = IDStack.back();\n\tImGuiID id = ImHashData(&n, sizeof(n), seed);\n\tImGuiContext& g = *Ctx;\n\tif (g.DebugHookIdInfo == id)\n\t\tImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);\n\treturn id;\n}\n\n// This is only used in rare/specific situations to manufacture an ID out of nowhere.\nImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)\n{\n\tImGuiID seed = IDStack.back();\n\tImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);\n\tImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);\n\treturn id;\n}\n\nstatic void SetCurrentWindow(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tg.CurrentWindow = window;\n\tg.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;\n\tif (window)\n\t{\n\t\tg.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();\n\t\tImGui::NavUpdateCurrentWindowIsScrollPushableX();\n\t}\n}\n\nvoid ImGui::GcCompactTransientMiscBuffers()\n{\n\tImGuiContext& g = *GImGui;\n\tg.ItemFlagsStack.clear();\n\tg.GroupStack.clear();\n\tTableGcCompactSettings();\n}\n\n// Free up/compact internal window buffers, we can use this when a window becomes unused.\n// Not freed:\n// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)\n// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.\nvoid ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)\n{\n\twindow->MemoryCompacted = true;\n\twindow->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;\n\twindow->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;\n\twindow->IDStack.clear();\n\twindow->DrawList->_ClearFreeMemory();\n\twindow->DC.ChildWindows.clear();\n\twindow->DC.ItemWidthStack.clear();\n\twindow->DC.TextWrapPosStack.clear();\n}\n\nvoid ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)\n{\n\t// We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.\n\t// The other buffers tends to amortize much faster.\n\twindow->MemoryCompacted = false;\n\twindow->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);\n\twindow->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);\n\twindow->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;\n}\n\nvoid ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Clear previous active id\n\tif (g.ActiveId != 0)\n\t{\n\t\t// While most behaved code would make an effort to not steal active id during window move/drag operations,\n\t\t// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch\n\t\t// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.\n\t\tif (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)\n\t\t{\n\t\t\tIMGUI_DEBUG_LOG_ACTIVEID(\"SetActiveID() cancel MovingWindow\\n\");\n\t\t\tg.MovingWindow = NULL;\n\t\t}\n\n\t\t// This could be written in a more general way (e.g associate a hook to ActiveId),\n\t\t// but since this is currently quite an exception we'll leave it as is.\n\t\t// One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId()\n\t\tif (g.InputTextState.ID == g.ActiveId)\n\t\t\tInputTextDeactivateHook(g.ActiveId);\n\t}\n\n\t// Set active id\n\tg.ActiveIdIsJustActivated = (g.ActiveId != id);\n\tif (g.ActiveIdIsJustActivated)\n\t{\n\t\tIMGUI_DEBUG_LOG_ACTIVEID(\"SetActiveID() old:0x%08X (window \\\"%s\\\") -> new:0x%08X (window \\\"%s\\\")\\n\", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : \"\", id, window ? window->Name : \"\");\n\t\tg.ActiveIdTimer = 0.0f;\n\t\tg.ActiveIdHasBeenPressedBefore = false;\n\t\tg.ActiveIdHasBeenEditedBefore = false;\n\t\tg.ActiveIdMouseButton = -1;\n\t\tif (id != 0)\n\t\t{\n\t\t\tg.LastActiveId = id;\n\t\t\tg.LastActiveIdTimer = 0.0f;\n\t\t}\n\t}\n\tg.ActiveId = id;\n\tg.ActiveIdAllowOverlap = false;\n\tg.ActiveIdNoClearOnFocusLoss = false;\n\tg.ActiveIdWindow = window;\n\tg.ActiveIdHasBeenEditedThisFrame = false;\n\tif (id)\n\t{\n\t\tg.ActiveIdIsAlive = id;\n\t\tg.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse;\n\t\tIM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None);\n\t}\n\n\t// Clear declaration of inputs claimed by the widget\n\t// (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)\n\tg.ActiveIdUsingNavDirMask = 0x00;\n\tg.ActiveIdUsingAllKeyboardKeys = false;\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tg.ActiveIdUsingNavInputMask = 0x00;\n#endif\n}\n\nvoid ImGui::ClearActiveID()\n{\n\tSetActiveID(0, NULL); // g.ActiveId = 0;\n}\n\nvoid ImGui::SetHoveredID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tg.HoveredId = id;\n\tg.HoveredIdAllowOverlap = false;\n\tif (id != 0 && g.HoveredIdPreviousFrame != id)\n\t\tg.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;\n}\n\nImGuiID ImGui::GetHoveredID()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;\n}\n\n// This is called by ItemAdd().\n// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID().\nvoid ImGui::KeepAliveID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveId == id)\n\t\tg.ActiveIdIsAlive = id;\n\tif (g.ActiveIdPreviousFrame == id)\n\t\tg.ActiveIdPreviousFrameIsAlive = true;\n}\n\nvoid ImGui::MarkItemEdited(ImGuiID id)\n{\n\t// This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().\n\t// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.\n\tImGuiContext& g = *GImGui;\n\tif (g.LockMarkEdited > 0)\n\t\treturn;\n\tif (g.ActiveId == id || g.ActiveId == 0)\n\t{\n\t\tg.ActiveIdHasBeenEditedThisFrame = true;\n\t\tg.ActiveIdHasBeenEditedBefore = true;\n\t}\n\n\t// We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343)\n\t// We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)\n\tIM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id);\n\n\t//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);\n\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;\n}\n\nbool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)\n{\n\t// An active popup disable hovering on other windows (apart from its own children)\n\t// FIXME-OPT: This could be cached/stored within the window.\n\tImGuiContext& g = *GImGui;\n\tif (g.NavWindow)\n\t\tif (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)\n\t\t\tif (focused_root_window->WasActive && focused_root_window != window->RootWindow)\n\t\t\t{\n\t\t\t\t// For the purpose of those flags we differentiate \"standard popup\" from \"modal popup\"\n\t\t\t\t// NB: The 'else' is important because Modal windows are also Popups.\n\t\t\t\tbool want_inhibit = false;\n\t\t\t\tif (focused_root_window->Flags & ImGuiWindowFlags_Modal)\n\t\t\t\t\twant_inhibit = true;\n\t\t\t\telse if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))\n\t\t\t\t\twant_inhibit = true;\n\n\t\t\t\t// Inhibit hover unless the window is within the stack of our modal/popup\n\t\t\t\tif (want_inhibit)\n\t\t\t\t\tif (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))\n\t\t\t\t\t\treturn false;\n\t\t\t}\n\treturn true;\n}\n\nstatic inline float CalcDelayFromHoveredFlags(ImGuiHoveredFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (flags & ImGuiHoveredFlags_DelayShort)\n\t\treturn g.Style.HoverDelayShort;\n\tif (flags & ImGuiHoveredFlags_DelayNormal)\n\t\treturn g.Style.HoverDelayNormal;\n\treturn 0.0f;\n}\n\n// This is roughly matching the behavior of internal-facing ItemHoverable()\n// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()\n// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId\nbool ImGui::IsItemHovered(ImGuiHoveredFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0 && \"Invalid flags for IsItemHovered()!\");\n\n\tif (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride))\n\t{\n\t\tif ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))\n\t\t\treturn false;\n\t\tif (!IsItemFocused())\n\t\t\treturn false;\n\n\t\tif (flags & ImGuiHoveredFlags_ForTooltip)\n\t\t\tflags |= g.Style.HoverFlagsForTooltipNav;\n\t}\n\telse\n\t{\n\t\t// Test for bounding box overlap, as updated as ItemAdd()\n\t\tImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;\n\t\tif (!(status_flags & ImGuiItemStatusFlags_HoveredRect))\n\t\t\treturn false;\n\n\t\tif (flags & ImGuiHoveredFlags_ForTooltip)\n\t\t\tflags |= g.Style.HoverFlagsForTooltipMouse;\n\n\t\tIM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0);   // Flags not supported by this function\n\n\t\t// Done with rectangle culling so we can perform heavier checks now\n\t\t// Test if we are hovering the right window (our window could be behind another window)\n\t\t// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)\n\t\t// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable\n\t\t// to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was\n\t\t// the test that has been running for a long while.\n\t\tif (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)\n\t\t\tif ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByWindow) == 0)\n\t\t\t\treturn false;\n\n\t\t// Test if another item is active (e.g. being dragged)\n\t\tconst ImGuiID id = g.LastItemData.ID;\n\t\tif ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)\n\t\t\tif (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)\n\t\t\t\treturn false;\n\n\t\t// Test if interactions on this window are blocked by an active popup or modal.\n\t\t// The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.\n\t\tif (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck))\n\t\t\treturn false;\n\n\t\t// Test if the item is disabled\n\t\tif ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))\n\t\t\treturn false;\n\n\t\t// Special handling for calling after Begin() which represent the title bar or tab.\n\t\t// When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.\n\t\tif (id == window->MoveId && window->WriteAccessed)\n\t\t\treturn false;\n\n\t\t// Test if using AllowOverlap and overlapped\n\t\tif ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0)\n\t\t\tif ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0)\n\t\t\t\tif (g.HoveredIdPreviousFrame != g.LastItemData.ID)\n\t\t\t\t\treturn false;\n\t}\n\n\t// Handle hover delay\n\t// (some ideas: https://www.nngroup.com/articles/timing-exposing-content)\n\tconst float delay = CalcDelayFromHoveredFlags(flags);\n\tif (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary))\n\t{\n\t\tImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect);\n\t\tif ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id))\n\t\t\tg.HoverItemDelayTimer = 0.0f;\n\t\tg.HoverItemDelayId = hover_delay_id;\n\n\t\t// When changing hovered item we requires a bit of stationary delay before activating hover timer,\n\t\t// but once unlocked on a given item we also moving.\n\t\t//if (g.HoverDelayTimer >= delay && (g.HoverDelayTimer - g.IO.DeltaTime < delay || g.MouseStationaryTimer - g.IO.DeltaTime < g.Style.HoverStationaryDelay)) { IMGUI_DEBUG_LOG(\"HoverDelayTimer = %f/%f, MouseStationaryTimer = %f\\n\", g.HoverDelayTimer, delay, g.MouseStationaryTimer); }\n\t\tif ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverItemUnlockedStationaryId != hover_delay_id)\n\t\t\treturn false;\n\n\t\tif (g.HoverItemDelayTimer < delay)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().\n// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call)\n// FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28.\n// If you used this in your legacy/custom widgets code:\n// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'.\n// - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable.\nbool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (g.HoveredWindow != window)\n\t\treturn false;\n\tif (!IsMouseHoveringRect(bb.Min, bb.Max))\n\t\treturn false;\n\n\tif (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)\n\t\treturn false;\n\tif (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)\n\t\treturn false;\n\n\t// Done with rectangle culling so we can perform heavier checks now.\n\tif (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))\n\t{\n\t\tg.HoveredIdDisabled = true;\n\t\treturn false;\n\t}\n\n\t// We exceptionally allow this function to be called with id==0 to allow using it for easy high-level\n\t// hover test in widgets code. We could also decide to split this function is two.\n\tif (id != 0)\n\t{\n\t\t// Drag source doesn't report as hovered\n\t\tif (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover))\n\t\t\treturn false;\n\n\t\tSetHoveredID(id);\n\n\t\t// AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match.\n\t\t// This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test.\n\t\tif (item_flags & ImGuiItemFlags_AllowOverlap)\n\t\t{\n\t\t\tg.HoveredIdAllowOverlap = true;\n\t\t\tif (g.HoveredIdPreviousFrame != id)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\t// When disabled we'll return false but still set HoveredId\n\tif (item_flags & ImGuiItemFlags_Disabled)\n\t{\n\t\t// Release active id if turning disabled\n\t\tif (g.ActiveId == id && id != 0)\n\t\t\tClearActiveID();\n\t\tg.HoveredIdDisabled = true;\n\t\treturn false;\n\t}\n\n\tif (id != 0)\n\t{\n\t\t// [DEBUG] Item Picker tool!\n\t\t// We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making\n\t\t// the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered\n\t\t// items if we performed the test in ItemAdd(), but that would incur a small runtime cost.\n\t\tif (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)\n\t\t\tGetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));\n\t\tif (g.DebugItemPickerBreakId == id)\n\t\t\tIM_DEBUG_BREAK();\n\t}\n\n\tif (g.NavDisableMouseHover)\n\t\treturn false;\n\n\treturn true;\n}\n\n// FIXME: This is inlined/duplicated in ItemAdd()\nbool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (!bb.Overlaps(window->ClipRect))\n\t\tif (id == 0 || (id != g.ActiveId && id != g.NavId))\n\t\t\tif (!g.LogEnabled)\n\t\t\t\treturn true;\n\treturn false;\n}\n\n// This is also inlined in ItemAdd()\n// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect.\nvoid ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)\n{\n\tImGuiContext& g = *GImGui;\n\tg.LastItemData.ID = item_id;\n\tg.LastItemData.InFlags = in_flags;\n\tg.LastItemData.StatusFlags = item_flags;\n\tg.LastItemData.Rect = g.LastItemData.NavRect = item_rect;\n}\n\nfloat ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)\n{\n\tif (wrap_pos_x < 0.0f)\n\t\treturn 0.0f;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (wrap_pos_x == 0.0f)\n\t{\n\t\t// We could decide to setup a default wrapping max point for auto-resizing windows,\n\t\t// or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?\n\t\t//if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))\n\t\t//    wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);\n\t\t//else\n\t\twrap_pos_x = window->WorkRect.Max.x;\n\t}\n\telse if (wrap_pos_x > 0.0f)\n\t{\n\t\twrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space\n\t}\n\n\treturn ImMax(wrap_pos_x - pos.x, 1.0f);\n}\n\n// IM_ALLOC() == ImGui::MemAlloc()\nvoid* ImGui::MemAlloc(size_t size)\n{\n\tif (ImGuiContext* ctx = GImGui)\n\t\tctx->IO.MetricsActiveAllocations++;\n\treturn (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);\n}\n\n// IM_FREE() == ImGui::MemFree()\nvoid ImGui::MemFree(void* ptr)\n{\n\tif (ptr)\n\t\tif (ImGuiContext* ctx = GImGui)\n\t\t\tctx->IO.MetricsActiveAllocations--;\n\treturn (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);\n}\n\nconst char* ImGui::GetClipboardText()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : \"\";\n}\n\nvoid ImGui::SetClipboardText(const char* text)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.IO.SetClipboardTextFn)\n\t\tg.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);\n}\n\nconst char* ImGui::GetVersion()\n{\n\treturn IMGUI_VERSION;\n}\n\nImGuiIO& ImGui::GetIO()\n{\n\tIM_ASSERT(GImGui != NULL && \"No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?\");\n\treturn GImGui->IO;\n}\n\n// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame()\nImDrawData* ImGui::GetDrawData()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiViewportP* viewport = g.Viewports[0];\n\treturn viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL;\n}\n\ndouble ImGui::GetTime()\n{\n\treturn GImGui->Time;\n}\n\nint ImGui::GetFrameCount()\n{\n\treturn GImGui->FrameCount;\n}\n\nstatic ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)\n{\n\t// Create the draw list on demand, because they are not frequently used for all viewports\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists));\n\tImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no];\n\tif (draw_list == NULL)\n\t{\n\t\tdraw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);\n\t\tdraw_list->_OwnerName = drawlist_name;\n\t\tviewport->BgFgDrawLists[drawlist_no] = draw_list;\n\t}\n\n\t// Our ImDrawList system requires that there is always a command\n\tif (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)\n\t{\n\t\tdraw_list->_ResetForNewFrame();\n\t\tdraw_list->PushTextureID(g.IO.Fonts->TexID);\n\t\tdraw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);\n\t\tviewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;\n\t}\n\treturn draw_list;\n}\n\nImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)\n{\n\treturn GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, \"##Background\");\n}\n\nImDrawList* ImGui::GetBackgroundDrawList()\n{\n\tImGuiContext& g = *GImGui;\n\treturn GetBackgroundDrawList(g.Viewports[0]);\n}\n\nImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)\n{\n\treturn GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, \"##Foreground\");\n}\n\nImDrawList* ImGui::GetForegroundDrawList()\n{\n\tImGuiContext& g = *GImGui;\n\treturn GetForegroundDrawList(g.Viewports[0]);\n}\n\nImDrawListSharedData* ImGui::GetDrawListSharedData()\n{\n\treturn &GImGui->DrawListSharedData;\n}\n\nvoid ImGui::StartMouseMovingWindow(ImGuiWindow* window)\n{\n\t// Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.\n\t// We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.\n\t// This is because we want ActiveId to be set even when the window is not permitted to move.\n\tImGuiContext& g = *GImGui;\n\tFocusWindow(window);\n\tSetActiveID(window->MoveId, window);\n\tg.NavDisableHighlight = true;\n\tg.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos;\n\tg.ActiveIdNoClearOnFocusLoss = true;\n\tSetActiveIdUsingAllKeyboardKeys();\n\n\tbool can_move_window = true;\n\tif ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))\n\t\tcan_move_window = false;\n\tif (can_move_window)\n\t\tg.MovingWindow = window;\n}\n\n// Handle mouse moving window\n// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()\n// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.\n// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,\n// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.\nvoid ImGui::UpdateMouseMovingWindowNewFrame()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.MovingWindow != NULL)\n\t{\n\t\t// We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).\n\t\t// We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.\n\t\tKeepAliveID(g.ActiveId);\n\t\tIM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);\n\t\tImGuiWindow* moving_window = g.MovingWindow->RootWindow;\n\t\tif (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))\n\t\t{\n\t\t\tImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;\n\t\t\tSetWindowPos(moving_window, pos, ImGuiCond_Always);\n\t\t\tFocusWindow(g.MovingWindow);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tg.MovingWindow = NULL;\n\t\t\tClearActiveID();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.\n\t\tif (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)\n\t\t{\n\t\t\tKeepAliveID(g.ActiveId);\n\t\t\tif (!g.IO.MouseDown[0])\n\t\t\t\tClearActiveID();\n\t\t}\n\t}\n}\n\n// Initiate moving window when clicking on empty space or title bar.\n// Handle left-click and right-click focus.\nvoid ImGui::UpdateMouseMovingWindowEndFrame()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveId != 0 || g.HoveredId != 0)\n\t\treturn;\n\n\t// Unless we just made a window/popup appear\n\tif (g.NavWindow && g.NavWindow->Appearing)\n\t\treturn;\n\n\t// Click on empty space to focus window and start moving\n\t// (after we're done with all our widgets)\n\tif (g.IO.MouseClicked[0])\n\t{\n\t\t// Handle the edge case of a popup being closed while clicking in its empty space.\n\t\t// If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.\n\t\tImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;\n\t\tconst bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);\n\n\t\tif (root_window != NULL && !is_closed_popup)\n\t\t{\n\t\t\tStartMouseMovingWindow(g.HoveredWindow); //-V595\n\n\t\t\t// Cancel moving if clicked outside of title bar\n\t\t\tif (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar))\n\t\t\t\tif (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))\n\t\t\t\t\tg.MovingWindow = NULL;\n\n\t\t\t// Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)\n\t\t\tif (g.HoveredIdDisabled)\n\t\t\t\tg.MovingWindow = NULL;\n\t\t}\n\t\telse if (root_window == NULL && g.NavWindow != NULL)\n\t\t{\n\t\t\t// Clicking on void disable focus\n\t\t\tFocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal);\n\t\t}\n\t}\n\n\t// With right mouse button we close popups without changing focus based on where the mouse is aimed\n\t// Instead, focus will be restored to the window under the bottom-most closed popup.\n\t// (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)\n\tif (g.IO.MouseClicked[1])\n\t{\n\t\t// Find the top-most window between HoveredWindow and the top-most Modal Window.\n\t\t// This is where we can trim the popup stack.\n\t\tImGuiWindow* modal = GetTopMostPopupModal();\n\t\tbool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal));\n\t\tClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);\n\t}\n}\n\nstatic bool IsWindowActiveAndVisible(ImGuiWindow* window)\n{\n\treturn (window->Active) && (!window->Hidden);\n}\n\n// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)\nvoid ImGui::UpdateHoveredWindowAndCaptureFlags()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\tg.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));\n\n\t// Find the window hovered by mouse:\n\t// - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.\n\t// - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.\n\t// - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.\n\tbool clear_hovered_windows = false;\n\tFindHoveredWindow();\n\n\t// Modal windows prevents mouse from hovering behind them.\n\tImGuiWindow* modal_window = GetTopMostPopupModal();\n\tif (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window))\n\t\tclear_hovered_windows = true;\n\n\t// Disabled mouse?\n\tif (io.ConfigFlags & ImGuiConfigFlags_NoMouse)\n\t\tclear_hovered_windows = true;\n\n\t// We track click ownership. When clicked outside of a window the click is owned by the application and\n\t// won't report hovering nor request capture even while dragging over our windows afterward.\n\tconst bool has_open_popup = (g.OpenPopupStack.Size > 0);\n\tconst bool has_open_modal = (modal_window != NULL);\n\tint mouse_earliest_down = -1;\n\tbool mouse_any_down = false;\n\tfor (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)\n\t{\n\t\tif (io.MouseClicked[i])\n\t\t{\n\t\t\tio.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;\n\t\t\tio.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;\n\t\t}\n\t\tmouse_any_down |= io.MouseDown[i];\n\t\tif (io.MouseDown[i])\n\t\t\tif (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])\n\t\t\t\tmouse_earliest_down = i;\n\t}\n\tconst bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];\n\tconst bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];\n\n\t// If mouse was first clicked outside of ImGui bounds we also cancel out hovering.\n\t// FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)\n\tconst bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;\n\tif (!mouse_avail && !mouse_dragging_extern_payload)\n\t\tclear_hovered_windows = true;\n\n\tif (clear_hovered_windows)\n\t\tg.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;\n\n\t// Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)\n\t// Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag\n\tif (g.WantCaptureMouseNextFrame != -1)\n\t{\n\t\tio.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0);\n\t}\n\telse\n\t{\n\t\tio.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;\n\t\tio.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;\n\t}\n\n\t// Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)\n\tif (g.WantCaptureKeyboardNextFrame != -1)\n\t\tio.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);\n\telse\n\t\tio.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);\n\tif (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))\n\t\tio.WantCaptureKeyboard = true;\n\n\t// Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible\n\tio.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;\n}\n\nvoid ImGui::NewFrame()\n{\n\tIM_ASSERT(GImGui != NULL && \"No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?\");\n\tImGuiContext& g = *GImGui;\n\n\t// Remove pending delete hooks before frame start.\n\t// This deferred removal avoid issues of removal while iterating the hook vector\n\tfor (int n = g.Hooks.Size - 1; n >= 0; n--)\n\t\tif (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_)\n\t\t\tg.Hooks.erase(&g.Hooks[n]);\n\n\tCallContextHooks(&g, ImGuiContextHookType_NewFramePre);\n\n\t// Check and assert for various common IO and Configuration mistakes\n\tErrorCheckNewFrameSanityChecks();\n\n\t// Load settings on first frame, save settings when modified (after a delay)\n\tUpdateSettings();\n\n\tg.Time += g.IO.DeltaTime;\n\tg.WithinFrameScope = true;\n\tg.FrameCount += 1;\n\tg.TooltipOverrideCount = 0;\n\tg.WindowsActiveCount = 0;\n\tg.MenusIdSubmittedThisFrame.resize(0);\n\n\t// Calculate frame-rate for the user, as a purely luxurious feature\n\tg.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];\n\tg.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;\n\tg.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);\n\tg.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame));\n\tg.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;\n\n\t// Process input queue (trickle as many events as possible), turn events into writes to IO structure\n\tg.InputEventsTrail.resize(0);\n\tUpdateInputEvents(g.IO.ConfigInputTrickleEventQueue);\n\n\t// Update viewports (after processing input queue, so io.MouseHoveredViewport is set)\n\tUpdateViewportsNewFrame();\n\n\t// Setup current font and draw list shared data\n\tg.IO.Fonts->Locked = true;\n\tSetCurrentFont(GetDefaultFont());\n\tIM_ASSERT(g.Font->IsLoaded());\n\tImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\tvirtual_space.Add(viewport->GetMainRect());\n\tg.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();\n\tg.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;\n\tg.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);\n\tg.DrawListSharedData.InitialFlags = ImDrawListFlags_None;\n\tif (g.Style.AntiAliasedLines)\n\t\tg.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;\n\tif (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))\n\t\tg.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;\n\tif (g.Style.AntiAliasedFill)\n\t\tg.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;\n\tif (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)\n\t\tg.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;\n\n\t// Mark rendering data as invalid to prevent user who may have a handle on it to use it.\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\tviewport->DrawDataP.Valid = false;\n\n\t// Drag and drop keep the source ID alive so even if the source disappear our state is consistent\n\tif (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)\n\t\tKeepAliveID(g.DragDropPayload.SourceId);\n\n\t// Update HoveredId data\n\tif (!g.HoveredIdPreviousFrame)\n\t\tg.HoveredIdTimer = 0.0f;\n\tif (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))\n\t\tg.HoveredIdNotActiveTimer = 0.0f;\n\tif (g.HoveredId)\n\t\tg.HoveredIdTimer += g.IO.DeltaTime;\n\tif (g.HoveredId && g.ActiveId != g.HoveredId)\n\t\tg.HoveredIdNotActiveTimer += g.IO.DeltaTime;\n\tg.HoveredIdPreviousFrame = g.HoveredId;\n\tg.HoveredId = 0;\n\tg.HoveredIdAllowOverlap = false;\n\tg.HoveredIdDisabled = false;\n\n\t// Clear ActiveID if the item is not alive anymore.\n\t// In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().\n\t// As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.\n\tif (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)\n\t{\n\t\tIMGUI_DEBUG_LOG_ACTIVEID(\"NewFrame(): ClearActiveID() because it isn't marked alive anymore!\\n\");\n\t\tClearActiveID();\n\t}\n\n\t// Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)\n\tif (g.ActiveId)\n\t\tg.ActiveIdTimer += g.IO.DeltaTime;\n\tg.LastActiveIdTimer += g.IO.DeltaTime;\n\tg.ActiveIdPreviousFrame = g.ActiveId;\n\tg.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;\n\tg.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;\n\tg.ActiveIdIsAlive = 0;\n\tg.ActiveIdHasBeenEditedThisFrame = false;\n\tg.ActiveIdPreviousFrameIsAlive = false;\n\tg.ActiveIdIsJustActivated = false;\n\tif (g.TempInputId != 0 && g.ActiveId != g.TempInputId)\n\t\tg.TempInputId = 0;\n\tif (g.ActiveId == 0)\n\t{\n\t\tg.ActiveIdUsingNavDirMask = 0x00;\n\t\tg.ActiveIdUsingAllKeyboardKeys = false;\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\t\tg.ActiveIdUsingNavInputMask = 0x00;\n#endif\n\t}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tif (g.ActiveId == 0)\n\t\tg.ActiveIdUsingNavInputMask = 0;\n\telse if (g.ActiveIdUsingNavInputMask != 0)\n\t{\n\t\t// If your custom widget code used:                 { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); }\n\t\t// Since IMGUI_VERSION_NUM >= 18804 it should be:   { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); }\n\t\tif (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel))\n\t\t\tSetKeyOwner(ImGuiKey_Escape, g.ActiveId);\n\t\tif (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel))\n\t\t\tIM_ASSERT(0); // Other values unsupported\n\t}\n#endif\n\n\t// Record when we have been stationary as this state is preserved while over same item.\n\t// FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values.\n\t// To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function.\n\tif (g.HoverItemDelayId != 0 && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay)\n\t\tg.HoverItemUnlockedStationaryId = g.HoverItemDelayId;\n\telse if (g.HoverItemDelayId == 0)\n\t\tg.HoverItemUnlockedStationaryId = 0;\n\tif (g.HoveredWindow != NULL && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay)\n\t\tg.HoverWindowUnlockedStationaryId = g.HoveredWindow->ID;\n\telse if (g.HoveredWindow == NULL)\n\t\tg.HoverWindowUnlockedStationaryId = 0;\n\n\t// Update hover delay for IsItemHovered() with delays and tooltips\n\tg.HoverItemDelayIdPreviousFrame = g.HoverItemDelayId;\n\tif (g.HoverItemDelayId != 0)\n\t{\n\t\tg.HoverItemDelayTimer += g.IO.DeltaTime;\n\t\tg.HoverItemDelayClearTimer = 0.0f;\n\t\tg.HoverItemDelayId = 0;\n\t}\n\telse if (g.HoverItemDelayTimer > 0.0f)\n\t{\n\t\t// This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps\n\t\t// We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle.\n\t\tg.HoverItemDelayClearTimer += g.IO.DeltaTime;\n\t\tif (g.HoverItemDelayClearTimer >= ImMax(0.25f, g.IO.DeltaTime * 2.0f)) // ~7 frames at 30 Hz + allow for low framerate\n\t\t\tg.HoverItemDelayTimer = g.HoverItemDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer.\n\t}\n\n\t// Drag and drop\n\tg.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;\n\tg.DragDropAcceptIdCurr = 0;\n\tg.DragDropAcceptIdCurrRectSurface = FLT_MAX;\n\tg.DragDropWithinSource = false;\n\tg.DragDropWithinTarget = false;\n\tg.DragDropHoldJustPressedId = 0;\n\n\t// Close popups on focus lost (currently wip/opt-in)\n\t//if (g.IO.AppFocusLost)\n\t//    ClosePopupsExceptModals();\n\n\t// Update keyboard input state\n\tUpdateKeyboardInputs();\n\n\t//IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl));\n\t//IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift));\n\t//IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt));\n\t//IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper));\n\n\t// Update gamepad/keyboard navigation\n\tNavUpdate();\n\n\t// Update mouse input state\n\tUpdateMouseInputs();\n\n\t// Find hovered window\n\t// (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)\n\tUpdateHoveredWindowAndCaptureFlags();\n\n\t// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)\n\tUpdateMouseMovingWindowNewFrame();\n\n\t// Background darkening/whitening\n\tif (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))\n\t\tg.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);\n\telse\n\t\tg.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);\n\n\tg.MouseCursor = ImGuiMouseCursor_Arrow;\n\tg.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;\n\n\t// Platform IME data: reset for the frame\n\tg.PlatformImeDataPrev = g.PlatformImeData;\n\tg.PlatformImeData.WantVisible = false;\n\n\t// Mouse wheel scrolling, scale\n\tUpdateMouseWheel();\n\n\t// Mark all windows as not visible and compact unused memory.\n\tIM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);\n\tconst float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;\n\tfor (ImGuiWindow* window : g.Windows)\n\t{\n\t\twindow->WasActive = window->Active;\n\t\twindow->Active = false;\n\t\twindow->WriteAccessed = false;\n\t\twindow->BeginCountPreviousFrame = window->BeginCount;\n\t\twindow->BeginCount = 0;\n\n\t\t// Garbage collect transient buffers of recently unused windows\n\t\tif (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)\n\t\t\tGcCompactTransientWindowBuffers(window);\n\t}\n\n\t// Garbage collect transient buffers of recently unused tables\n\tfor (int i = 0; i < g.TablesLastTimeActive.Size; i++)\n\t\tif (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)\n\t\t\tTableGcCompactTransientBuffers(g.Tables.GetByIndex(i));\n\tfor (ImGuiTableTempData& table_temp_data : g.TablesTempData)\n\t\tif (table_temp_data.LastTimeActive >= 0.0f && table_temp_data.LastTimeActive < memory_compact_start_time)\n\t\t\tTableGcCompactTransientBuffers(&table_temp_data);\n\tif (g.GcCompactAll)\n\t\tGcCompactTransientMiscBuffers();\n\tg.GcCompactAll = false;\n\n\t// Closing the focused window restore focus to the first active root window in descending z-order\n\tif (g.NavWindow && !g.NavWindow->WasActive)\n\t\tFocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild);\n\n\t// No window should be open at the beginning of the frame.\n\t// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.\n\tg.CurrentWindowStack.resize(0);\n\tg.BeginPopupStack.resize(0);\n\tg.ItemFlagsStack.resize(0);\n\tg.ItemFlagsStack.push_back(ImGuiItemFlags_None);\n\tg.GroupStack.resize(0);\n\n\t// [DEBUG] Update debug features\n\tUpdateDebugToolItemPicker();\n\tUpdateDebugToolStackQueries();\n\tif (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0)\n\t\tg.DebugLocateId = 0;\n\tif (g.DebugLogClipperAutoDisableFrames > 0 && --g.DebugLogClipperAutoDisableFrames == 0)\n\t{\n\t\tDebugLog(\"(Auto-disabled ImGuiDebugLogFlags_EventClipper to avoid spamming)\\n\");\n\t\tg.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper;\n\t}\n\n\t// Create implicit/fallback window - which we will only render it if the user has added something to it.\n\t// We don't use \"Debug\" to avoid colliding with user trying to create a \"Debug\" window with custom flags.\n\t// This fallback is particularly important as it prevents ImGui:: calls from crashing.\n\tg.WithinFrameScopeWithImplicitWindow = true;\n\tSetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);\n\tBegin(\"Debug##Default\");\n\tIM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);\n\n\t// [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack,\n\t// allowing to validate correct Begin/End behavior in user code.\n\tif (g.IO.ConfigDebugBeginReturnValueLoop)\n\t\tg.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10);\n\telse\n\t\tg.DebugBeginReturnValueCullDepth = -1;\n\n\tCallContextHooks(&g, ImGuiContextHookType_NewFramePost);\n}\n\n// FIXME: Add a more explicit sort order in the window structure.\nstatic int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)\n{\n\tconst ImGuiWindow* const a = *(const ImGuiWindow* const*)lhs;\n\tconst ImGuiWindow* const b = *(const ImGuiWindow* const*)rhs;\n\tif (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))\n\t\treturn d;\n\tif (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))\n\t\treturn d;\n\treturn (a->BeginOrderWithinParent - b->BeginOrderWithinParent);\n}\n\nstatic void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)\n{\n\tout_sorted_windows->push_back(window);\n\tif (window->Active)\n\t{\n\t\tint count = window->DC.ChildWindows.Size;\n\t\tImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);\n\t\tfor (int i = 0; i < count; i++)\n\t\t{\n\t\t\tImGuiWindow* child = window->DC.ChildWindows[i];\n\t\t\tif (child->Active)\n\t\t\t\tAddWindowToSortBuffer(out_sorted_windows, child);\n\t\t}\n\t}\n}\n\nstatic void AddWindowToDrawData(ImGuiWindow* window, int layer)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiViewportP* viewport = g.Viewports[0];\n\tg.IO.MetricsRenderWindows++;\n\tif (window->DrawList->_Splitter._Count > 1)\n\t\twindow->DrawList->ChannelsMerge(); // Merge if user forgot to merge back. Also required in Docking branch for ImGuiWindowFlags_DockNodeHost windows.\n\tImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList);\n\tfor (ImGuiWindow* child : window->DC.ChildWindows)\n\t\tif (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active\n\t\t\tAddWindowToDrawData(child, layer);\n}\n\nstatic inline int GetWindowDisplayLayer(ImGuiWindow* window)\n{\n\treturn (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;\n}\n\n// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)\nstatic inline void AddRootWindowToDrawData(ImGuiWindow* window)\n{\n\tAddWindowToDrawData(window, GetWindowDisplayLayer(window));\n}\n\nstatic void FlattenDrawDataIntoSingleLayer(ImDrawDataBuilder* builder)\n{\n\tint n = builder->Layers[0]->Size;\n\tint full_size = n;\n\tfor (int i = 1; i < IM_ARRAYSIZE(builder->Layers); i++)\n\t\tfull_size += builder->Layers[i]->Size;\n\tbuilder->Layers[0]->resize(full_size);\n\tfor (int layer_n = 1; layer_n < IM_ARRAYSIZE(builder->Layers); layer_n++)\n\t{\n\t\tImVector<ImDrawList*>* layer = builder->Layers[layer_n];\n\t\tif (layer->empty())\n\t\t\tcontinue;\n\t\tmemcpy(builder->Layers[0]->Data + n, layer->Data, layer->Size * sizeof(ImDrawList*));\n\t\tn += layer->Size;\n\t\tlayer->resize(0);\n\t}\n}\n\nstatic void InitViewportDrawData(ImGuiViewportP* viewport)\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tImDrawData* draw_data = &viewport->DrawDataP;\n\n\tviewport->DrawDataBuilder.Layers[0] = &draw_data->CmdLists;\n\tviewport->DrawDataBuilder.Layers[1] = &viewport->DrawDataBuilder.LayerData1;\n\tviewport->DrawDataBuilder.Layers[0]->resize(0);\n\tviewport->DrawDataBuilder.Layers[1]->resize(0);\n\n\tdraw_data->Valid = true;\n\tdraw_data->CmdListsCount = 0;\n\tdraw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;\n\tdraw_data->DisplayPos = viewport->Pos;\n\tdraw_data->DisplaySize = viewport->Size;\n\tdraw_data->FramebufferScale = io.DisplayFramebufferScale;\n\tdraw_data->OwnerViewport = viewport;\n}\n\n// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.\n// - When using this function it is sane to ensure that float are perfectly rounded to integer values,\n//   so that e.g. (int)(max.x-min.x) in user's render produce correct result.\n// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():\n//   some frequently called functions which to modify both channels and clipping simultaneously tend to use the\n//   more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.\nvoid ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);\n\twindow->ClipRect = window->DrawList->_ClipRectStack.back();\n}\n\nvoid ImGui::PopClipRect()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DrawList->PopClipRect();\n\twindow->ClipRect = window->DrawList->_ClipRectStack.back();\n}\n\nstatic void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport();\n\tImRect viewport_rect = viewport->GetMainRect();\n\n\t// Draw behind window by moving the draw command at the FRONT of the draw list\n\t{\n\t\t// We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows,\n\t\t// and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.\n\t\t// FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.\n\t\tImDrawList* draw_list = window->RootWindow->DrawList;\n\t\tif (draw_list->CmdBuffer.Size == 0)\n\t\t\tdraw_list->AddDrawCmd();\n\t\tdraw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)\n\t\tdraw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);\n\t\tImDrawCmd cmd = draw_list->CmdBuffer.back();\n\t\tIM_ASSERT(cmd.ElemCount == 6);\n\t\tdraw_list->CmdBuffer.pop_back();\n\t\tdraw_list->CmdBuffer.push_front(cmd);\n\t\tdraw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.\n\t\tdraw_list->PopClipRect();\n\t}\n}\n\nImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* bottom_most_visible_window = parent_window;\n\tfor (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)\n\t{\n\t\tImGuiWindow* window = g.Windows[i];\n\t\tif (window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\t\tcontinue;\n\t\tif (!IsWindowWithinBeginStackOf(window, parent_window))\n\t\t\tbreak;\n\t\tif (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))\n\t\t\tbottom_most_visible_window = window;\n\t}\n\treturn bottom_most_visible_window;\n}\n\nstatic void ImGui::RenderDimmedBackgrounds()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();\n\tif (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)\n\t\treturn;\n\tconst bool dim_bg_for_modal = (modal_window != NULL);\n\tconst bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);\n\tif (!dim_bg_for_modal && !dim_bg_for_window_list)\n\t\treturn;\n\n\tif (dim_bg_for_modal)\n\t{\n\t\t// Draw dimming behind modal or a begin stack child, whichever comes first in draw order.\n\t\tImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window);\n\t\tRenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio));\n\t}\n\telse if (dim_bg_for_window_list)\n\t{\n\t\t// Draw dimming behind CTRL+Tab target window\n\t\tRenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));\n\n\t\t// Draw border around CTRL+Tab target window\n\t\tImGuiWindow* window = g.NavWindowingTargetAnim;\n\t\tImGuiViewport* viewport = GetMainViewport();\n\t\tfloat distance = g.FontSize;\n\t\tImRect bb = window->Rect();\n\t\tbb.Expand(distance);\n\t\tif (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)\n\t\t\tbb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward\n\t\tif (window->DrawList->CmdBuffer.Size == 0)\n\t\t\twindow->DrawList->AddDrawCmd();\n\t\twindow->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);\n\t\twindow->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f);\n\t\twindow->DrawList->PopClipRect();\n\t}\n}\n\n// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.\nvoid ImGui::EndFrame()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.Initialized);\n\n\t// Don't process EndFrame() multiple times.\n\tif (g.FrameCountEnded == g.FrameCount)\n\t\treturn;\n\tIM_ASSERT(g.WithinFrameScope && \"Forgot to call ImGui::NewFrame()?\");\n\n\tCallContextHooks(&g, ImGuiContextHookType_EndFramePre);\n\n\tErrorCheckEndFrameSanityChecks();\n\n\t// Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)\n\tImGuiPlatformImeData* ime_data = &g.PlatformImeData;\n\tif (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)\n\t{\n\t\tIMGUI_DEBUG_LOG_IO(\"[io] Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\\n\", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);\n\t\tImGuiViewport* viewport = GetMainViewport();\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\t\tif (viewport->PlatformHandleRaw == NULL && g.IO.ImeWindowHandle != NULL)\n\t\t{\n\t\t\tviewport->PlatformHandleRaw = g.IO.ImeWindowHandle;\n\t\t\tg.IO.SetPlatformImeDataFn(viewport, ime_data);\n\t\t\tviewport->PlatformHandleRaw = NULL;\n\t\t}\n\t\telse\n#endif\n\t\t{\n\t\t\tg.IO.SetPlatformImeDataFn(viewport, ime_data);\n\t\t}\n\t}\n\n\t// Hide implicit/fallback \"Debug\" window if it hasn't been used\n\tg.WithinFrameScopeWithImplicitWindow = false;\n\tif (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)\n\t\tg.CurrentWindow->Active = false;\n\tEnd();\n\n\t// Update navigation: CTRL+Tab, wrap-around requests\n\tNavEndFrame();\n\n\t// Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)\n\tif (g.DragDropActive)\n\t{\n\t\tbool is_delivered = g.DragDropPayload.Delivery;\n\t\tbool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));\n\t\tif (is_delivered || is_elapsed)\n\t\t\tClearDragDrop();\n\t}\n\n\t// Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.\n\tif (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))\n\t{\n\t\tg.DragDropWithinSource = true;\n\t\tSetTooltip(\"...\");\n\t\tg.DragDropWithinSource = false;\n\t}\n\n\t// End frame\n\tg.WithinFrameScope = false;\n\tg.FrameCountEnded = g.FrameCount;\n\n\t// Initiate moving window + handle left-click and right-click focus\n\tUpdateMouseMovingWindowEndFrame();\n\n\t// Sort the window list so that all child windows are after their parent\n\t// We cannot do that on FocusWindow() because children may not exist yet\n\tg.WindowsTempSortBuffer.resize(0);\n\tg.WindowsTempSortBuffer.reserve(g.Windows.Size);\n\tfor (ImGuiWindow* window : g.Windows)\n\t{\n\t\tif (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it\n\t\t\tcontinue;\n\t\tAddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);\n\t}\n\n\t// This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.\n\tIM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);\n\tg.Windows.swap(g.WindowsTempSortBuffer);\n\tg.IO.MetricsActiveWindows = g.WindowsActiveCount;\n\n\t// Unlock font atlas\n\tg.IO.Fonts->Locked = false;\n\n\t// Clear Input data for next frame\n\tg.IO.AppFocusLost = false;\n\tg.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;\n\tg.IO.InputQueueCharacters.resize(0);\n\n\tCallContextHooks(&g, ImGuiContextHookType_EndFramePost);\n}\n\n// Prepare the data for rendering so you can call GetDrawData()\n// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all:\n// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend)\nvoid ImGui::Render()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.Initialized);\n\n\tif (g.FrameCountEnded != g.FrameCount)\n\t\tEndFrame();\n\tif (g.FrameCountRendered == g.FrameCount)\n\t\treturn;\n\tg.FrameCountRendered = g.FrameCount;\n\n\tg.IO.MetricsRenderWindows = 0;\n\tCallContextHooks(&g, ImGuiContextHookType_RenderPre);\n\n\t// Draw modal/window whitening backgrounds\n\tRenderDimmedBackgrounds();\n\n\t// Add background ImDrawList (for each active viewport)\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t{\n\t\tInitViewportDrawData(viewport);\n\t\tif (viewport->BgFgDrawLists[0] != NULL)\n\t\t\tAddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));\n\t}\n\n\t// Add ImDrawList to render\n\tImGuiWindow* windows_to_render_top_most[2];\n\twindows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;\n\twindows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);\n\tfor (ImGuiWindow* window : g.Windows)\n\t{\n\t\tIM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive \"warning C6011: Dereferencing NULL pointer 'window'\"\n\t\tif (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])\n\t\t\tAddRootWindowToDrawData(window);\n\t}\n\tfor (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)\n\t\tif (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window\n\t\t\tAddRootWindowToDrawData(windows_to_render_top_most[n]);\n\n\t// Draw software mouse cursor if requested by io.MouseDrawCursor flag\n\tif (g.IO.MouseDrawCursor && g.MouseCursor != ImGuiMouseCursor_None)\n\t\tRenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));\n\n\t// Setup ImDrawData structures for end-user\n\tg.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t{\n\t\tFlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder);\n\n\t\t// Add foreground ImDrawList (for each active viewport)\n\t\tif (viewport->BgFgDrawLists[1] != NULL)\n\t\t\tAddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));\n\n\t\t// We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch).\n\t\tImDrawData* draw_data = &viewport->DrawDataP;\n\t\tIM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount);\n\t\tfor (ImDrawList* draw_list : draw_data->CmdLists)\n\t\t\tdraw_list->_PopUnusedDrawCmd();\n\n\t\tg.IO.MetricsRenderVertices += draw_data->TotalVtxCount;\n\t\tg.IO.MetricsRenderIndices += draw_data->TotalIdxCount;\n\t}\n\n\tCallContextHooks(&g, ImGuiContextHookType_RenderPost);\n}\n\n// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.\n// CalcTextSize(\"\") should return ImVec2(0.0f, g.FontSize)\nImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)\n{\n\tImGuiContext& g = *GImGui;\n\n\tconst char* text_display_end;\n\tif (hide_text_after_double_hash)\n\t\ttext_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string\n\telse\n\t\ttext_display_end = text_end;\n\n\tImFont* font = g.Font;\n\tconst float font_size = g.FontSize;\n\tif (text == text_display_end)\n\t\treturn ImVec2(0.0f, font_size);\n\tImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);\n\n\t// Round\n\t// FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.\n\t// FIXME: Investigate using ceilf or e.g.\n\t// - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c\n\t// - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html\n\ttext_size.x = IM_FLOOR(text_size.x + 0.99999f);\n\n\treturn text_size;\n}\n\n// Find window given position, search front-to-back\n// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically\n// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is\n// called, aka before the next Begin(). Moving window isn't affected.\nstatic void FindHoveredWindow()\n{\n\tImGuiContext& g = *GImGui;\n\n\tImGuiWindow* hovered_window = NULL;\n\tImGuiWindow* hovered_window_ignoring_moving_window = NULL;\n\tif (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))\n\t\thovered_window = g.MovingWindow;\n\n\tImVec2 padding_regular = g.Style.TouchExtraPadding;\n\tImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;\n\tfor (int i = g.Windows.Size - 1; i >= 0; i--)\n\t{\n\t\tImGuiWindow* window = g.Windows[i];\n\t\tIM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.\n\t\tif (!window->Active || window->Hidden)\n\t\t\tcontinue;\n\t\tif (window->Flags & ImGuiWindowFlags_NoMouseInputs)\n\t\t\tcontinue;\n\n\t\t// Using the clipped AABB, a child window will typically be clipped by its parent (not always)\n\t\tImRect bb(window->OuterRectClipped);\n\t\tif (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))\n\t\t\tbb.Expand(padding_regular);\n\t\telse\n\t\t\tbb.Expand(padding_for_resize);\n\t\tif (!bb.Contains(g.IO.MousePos))\n\t\t\tcontinue;\n\n\t\t// Support for one rectangular hole in any given window\n\t\t// FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)\n\t\tif (window->HitTestHoleSize.x != 0)\n\t\t{\n\t\t\tImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);\n\t\t\tImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);\n\t\t\tif (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tif (hovered_window == NULL)\n\t\t\thovered_window = window;\n\t\tIM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.\n\t\tif (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))\n\t\t\thovered_window_ignoring_moving_window = window;\n\t\tif (hovered_window && hovered_window_ignoring_moving_window)\n\t\t\tbreak;\n\t}\n\n\tg.HoveredWindow = hovered_window;\n\tg.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;\n}\n\nbool ImGui::IsItemActive()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveId)\n\t\treturn g.ActiveId == g.LastItemData.ID;\n\treturn false;\n}\n\nbool ImGui::IsItemActivated()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveId)\n\t\tif (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID)\n\t\t\treturn true;\n\treturn false;\n}\n\nbool ImGui::IsItemDeactivated()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated)\n\t\treturn (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;\n\treturn (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID);\n}\n\nbool ImGui::IsItemDeactivatedAfterEdit()\n{\n\tImGuiContext& g = *GImGui;\n\treturn IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));\n}\n\n// == GetItemID() == GetFocusID()\nbool ImGui::IsItemFocused()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.NavId != g.LastItemData.ID || g.NavId == 0)\n\t\treturn false;\n\treturn true;\n}\n\n// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()!\n// Most widgets have specific reactions based on mouse-up/down state, mouse position etc.\nbool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)\n{\n\treturn IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);\n}\n\nbool ImGui::IsItemToggledOpen()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;\n}\n\nbool ImGui::IsItemToggledSelection()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;\n}\n\nbool ImGui::IsAnyItemHovered()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;\n}\n\nbool ImGui::IsAnyItemActive()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.ActiveId != 0;\n}\n\nbool ImGui::IsAnyItemFocused()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.NavId != 0 && !g.NavDisableHighlight;\n}\n\nbool ImGui::IsItemVisible()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) != 0;\n}\n\nbool ImGui::IsItemEdited()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0;\n}\n\n// Allow next item to be overlapped by subsequent items.\n// This works by requiring HoveredId to match for two subsequent frames,\n// so if a following items overwrite it our interactions will naturally be disabled.\nvoid ImGui::SetNextItemAllowOverlap()\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextItemData.ItemFlags |= ImGuiItemFlags_AllowOverlap;\n}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.\n// FIXME-LEGACY: Use SetNextItemAllowOverlap() *before* your item instead.\nvoid ImGui::SetItemAllowOverlap()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiID id = g.LastItemData.ID;\n\tif (g.HoveredId == id)\n\t\tg.HoveredIdAllowOverlap = true;\n\tif (g.ActiveId == id) // Before we made this obsolete, most calls to SetItemAllowOverlap() used to avoid this path by testing g.ActiveId != id.\n\t\tg.ActiveIdAllowOverlap = true;\n}\n#endif\n\n// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function.\nvoid ImGui::SetActiveIdUsingAllKeyboardKeys()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.ActiveId != 0);\n\tg.ActiveIdUsingNavDirMask = (1 << ImGuiDir_COUNT) - 1;\n\tg.ActiveIdUsingAllKeyboardKeys = true;\n\tNavMoveRequestCancel();\n}\n\nImGuiID ImGui::GetItemID()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.LastItemData.ID;\n}\n\nImVec2 ImGui::GetItemRectMin()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.LastItemData.Rect.Min;\n}\n\nImVec2 ImGui::GetItemRectMax()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.LastItemData.Rect.Max;\n}\n\nImVec2 ImGui::GetItemRectSize()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.LastItemData.Rect.GetSize();\n}\n\nbool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* parent_window = g.CurrentWindow;\n\n\tflags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;\n\tflags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag\n\n\t// Size\n\tconst ImVec2 content_avail = GetContentRegionAvail();\n\tImVec2 size = ImFloor(size_arg);\n\tconst int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);\n\tif (size.x <= 0.0f)\n\t\tsize.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too many issues)\n\tif (size.y <= 0.0f)\n\t\tsize.y = ImMax(content_avail.y + size.y, 4.0f);\n\tSetNextWindowSize(size);\n\n\t// Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value.\n\tconst char* temp_window_name;\n\tif (name)\n\t\tImFormatStringToTempBuffer(&temp_window_name, NULL, \"%s/%s_%08X\", parent_window->Name, name, id);\n\telse\n\t\tImFormatStringToTempBuffer(&temp_window_name, NULL, \"%s/%08X\", parent_window->Name, id);\n\n\tconst float backup_border_size = g.Style.ChildBorderSize;\n\tif (!border)\n\t\tg.Style.ChildBorderSize = 0.0f;\n\tbool ret = Begin(temp_window_name, NULL, flags);\n\tg.Style.ChildBorderSize = backup_border_size;\n\n\tImGuiWindow* child_window = g.CurrentWindow;\n\tchild_window->ChildId = id;\n\tchild_window->AutoFitChildAxises = (ImS8)auto_fit_axises;\n\n\t// Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.\n\t// While this is not really documented/defined, it seems that the expected thing to do.\n\tif (child_window->BeginCount == 1)\n\t\tparent_window->DC.CursorPos = child_window->Pos;\n\n\t// Process navigation-in immediately so NavInit can run on first frame\n\t// Can enter a child if (A) it has navigatable items or (B) it can be scrolled.\n\tconst ImGuiID temp_id_for_activation = ImHashStr(\"##Child\", 0, id);\n\tif (g.ActiveId == temp_id_for_activation)\n\t\tClearActiveID();\n\tif (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))\n\t{\n\t\tFocusWindow(child_window);\n\t\tNavInitWindow(child_window, false);\n\t\tSetActiveID(temp_id_for_activation, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item\n\t\tg.ActiveIdSource = g.NavInputSource;\n\t}\n\treturn ret;\n}\n\nbool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\treturn BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);\n}\n\nbool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)\n{\n\tIM_ASSERT(id != 0);\n\treturn BeginChildEx(NULL, id, size_arg, border, extra_flags);\n}\n\nvoid ImGui::EndChild()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tIM_ASSERT(g.WithinEndChild == false);\n\tIM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() calls\n\n\tg.WithinEndChild = true;\n\tif (window->BeginCount > 1)\n\t{\n\t\tEnd();\n\t}\n\telse\n\t{\n\t\tImVec2 sz = window->Size;\n\t\tif (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f\n\t\t\tsz.x = ImMax(4.0f, sz.x);\n\t\tif (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))\n\t\t\tsz.y = ImMax(4.0f, sz.y);\n\t\tEnd();\n\n\t\tImGuiWindow* parent_window = g.CurrentWindow;\n\t\tImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);\n\t\tItemSize(sz);\n\t\tif ((window->DC.NavLayersActiveMask != 0 || window->DC.NavWindowHasScrollY) && !(window->Flags & ImGuiWindowFlags_NavFlattened))\n\t\t{\n\t\t\tItemAdd(bb, window->ChildId);\n\t\t\tRenderNavHighlight(bb, window->ChildId);\n\n\t\t\t// When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying)\n\t\t\tif (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)\n\t\t\t\tRenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Not navigable into\n\t\t\tItemAdd(bb, 0);\n\n\t\t\t// But when flattened we directly reach items, adjust active layer mask accordingly\n\t\t\tif (window->Flags & ImGuiWindowFlags_NavFlattened)\n\t\t\t\tparent_window->DC.NavLayersActiveMaskNext |= window->DC.NavLayersActiveMaskNext;\n\t\t}\n\t\tif (g.HoveredWindow == window)\n\t\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;\n\t}\n\tg.WithinEndChild = false;\n\tg.LogLinePosY = -FLT_MAX; // To enforce a carriage return\n}\n\n// Helper to create a child window / scrolling region that looks like a normal widget frame.\nbool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tPushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);\n\tPushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);\n\tPushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);\n\tPushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);\n\tbool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);\n\tPopStyleVar(3);\n\tPopStyleColor();\n\treturn ret;\n}\n\nvoid ImGui::EndChildFrame()\n{\n\tEndChild();\n}\n\nstatic void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)\n{\n\twindow->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);\n\twindow->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags);\n\twindow->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);\n}\n\nImGuiWindow* ImGui::FindWindowByID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\treturn (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);\n}\n\nImGuiWindow* ImGui::FindWindowByName(const char* name)\n{\n\tImGuiID id = ImHashStr(name);\n\treturn FindWindowByID(id);\n}\n\nstatic void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)\n{\n\twindow->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));\n\tif (settings->Size.x > 0 && settings->Size.y > 0)\n\t\twindow->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));\n\twindow->Collapsed = settings->Collapsed;\n}\n\nstatic void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\tconst bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0);\n\tconst bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild;\n\tif ((just_created || child_flag_changed) && !new_is_explicit_child)\n\t{\n\t\tIM_ASSERT(!g.WindowsFocusOrder.contains(window));\n\t\tg.WindowsFocusOrder.push_back(window);\n\t\twindow->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);\n\t}\n\telse if (!just_created && child_flag_changed && new_is_explicit_child)\n\t{\n\t\tIM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window);\n\t\tfor (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++)\n\t\t\tg.WindowsFocusOrder[n]->FocusOrder--;\n\t\tg.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder);\n\t\twindow->FocusOrder = -1;\n\t}\n\twindow->IsExplicitChild = new_is_explicit_child;\n}\n\nstatic void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)\n{\n\t// Initial window state with e.g. default/arbitrary window position\n\t// Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.\n\tconst ImGuiViewport* main_viewport = ImGui::GetMainViewport();\n\twindow->Pos = main_viewport->Pos + ImVec2(60, 60);\n\twindow->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;\n\n\tif (settings != NULL)\n\t{\n\t\tSetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);\n\t\tApplyWindowSettings(window, settings);\n\t}\n\twindow->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values\n\n\tif ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)\n\t{\n\t\twindow->AutoFitFramesX = window->AutoFitFramesY = 2;\n\t\twindow->AutoFitOnlyGrows = false;\n\t}\n\telse\n\t{\n\t\tif (window->Size.x <= 0.0f)\n\t\t\twindow->AutoFitFramesX = 2;\n\t\tif (window->Size.y <= 0.0f)\n\t\t\twindow->AutoFitFramesY = 2;\n\t\twindow->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);\n\t}\n}\n\nstatic ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)\n{\n\t// Create window the first time\n\t//IMGUI_DEBUG_LOG(\"CreateNewWindow '%s', flags = 0x%08X\\n\", name, flags);\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);\n\twindow->Flags = flags;\n\tg.WindowsById.SetVoidPtr(window->ID, window);\n\n\tImGuiWindowSettings* settings = NULL;\n\tif (!(flags & ImGuiWindowFlags_NoSavedSettings))\n\t\tif ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0)\n\t\t\twindow->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);\n\n\tInitOrLoadWindowSettings(window, settings);\n\n\tif (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)\n\t\tg.Windows.push_front(window); // Quite slow but rare and only once\n\telse\n\t\tg.Windows.push_back(window);\n\n\treturn window;\n}\n\nstatic ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired)\n{\n\tImGuiContext& g = *GImGui;\n\tImVec2 new_size = size_desired;\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)\n\t{\n\t\t// Using -1,-1 on either X/Y axis to preserve the current size.\n\t\tImRect cr = g.NextWindowData.SizeConstraintRect;\n\t\tnew_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;\n\t\tnew_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;\n\t\tif (g.NextWindowData.SizeCallback)\n\t\t{\n\t\t\tImGuiSizeCallbackData data;\n\t\t\tdata.UserData = g.NextWindowData.SizeCallbackUserData;\n\t\t\tdata.Pos = window->Pos;\n\t\t\tdata.CurrentSize = window->SizeFull;\n\t\t\tdata.DesiredSize = new_size;\n\t\t\tg.NextWindowData.SizeCallback(&data);\n\t\t\tnew_size = data.DesiredSize;\n\t\t}\n\t\tnew_size.x = IM_FLOOR(new_size.x);\n\t\tnew_size.y = IM_FLOOR(new_size.y);\n\t}\n\n\t// Minimum size\n\tif (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))\n\t{\n\t\tImGuiWindow* window_for_height = window;\n\t\tnew_size = ImMax(new_size, g.Style.WindowMinSize);\n\t\tconst float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f);\n\t\tnew_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows\n\t}\n\treturn new_size;\n}\n\nstatic void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal)\n{\n\tbool preserve_old_content_sizes = false;\n\tif (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)\n\t\tpreserve_old_content_sizes = true;\n\telse if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)\n\t\tpreserve_old_content_sizes = true;\n\tif (preserve_old_content_sizes)\n\t{\n\t\t*content_size_current = window->ContentSize;\n\t\t*content_size_ideal = window->ContentSizeIdeal;\n\t\treturn;\n\t}\n\n\tcontent_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);\n\tcontent_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);\n\tcontent_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x);\n\tcontent_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y);\n}\n\nstatic ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiStyle& style = g.Style;\n\tconst float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x;\n\tconst float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y;\n\tImVec2 size_pad = window->WindowPadding * 2.0f;\n\tImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars);\n\tif (window->Flags & ImGuiWindowFlags_Tooltip)\n\t{\n\t\t// Tooltip always resize\n\t\treturn size_desired;\n\t}\n\telse\n\t{\n\t\t// Maximum window size is determined by the viewport size or monitor size\n\t\tconst bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;\n\t\tconst bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;\n\t\tImVec2 size_min = style.WindowMinSize;\n\t\tif (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)\n\t\t\tsize_min = ImMin(size_min, ImVec2(4.0f, 4.0f));\n\n\t\tImVec2 avail_size = ImGui::GetMainViewport()->WorkSize;\n\t\tImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f));\n\n\t\t// When the window cannot fit all contents (either because of constraints, either because screen is too small),\n\t\t// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.\n\t\tImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);\n\t\tbool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);\n\t\tbool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);\n\t\tif (will_have_scrollbar_x)\n\t\t\tsize_auto_fit.y += style.ScrollbarSize;\n\t\tif (will_have_scrollbar_y)\n\t\t\tsize_auto_fit.x += style.ScrollbarSize;\n\t\treturn size_auto_fit;\n\t}\n}\n\nImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window)\n{\n\tImVec2 size_contents_current;\n\tImVec2 size_contents_ideal;\n\tCalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal);\n\tImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal);\n\tImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);\n\treturn size_final;\n}\n\nstatic ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window)\n{\n\tif (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))\n\t\treturn ImGuiCol_PopupBg;\n\tif (window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\treturn ImGuiCol_ChildBg;\n\treturn ImGuiCol_WindowBg;\n}\n\nstatic void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)\n{\n\tImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left\n\tImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right\n\tImVec2 size_expected = pos_max - pos_min;\n\tImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);\n\t*out_pos = pos_min;\n\tif (corner_norm.x == 0.0f)\n\t\tout_pos->x -= (size_constrained.x - size_expected.x);\n\tif (corner_norm.y == 0.0f)\n\t\tout_pos->y -= (size_constrained.y - size_expected.y);\n\t*out_size = size_constrained;\n}\n\n// Data for resizing from corner\nstruct ImGuiResizeGripDef\n{\n\tImVec2  CornerPosN;\n\tImVec2  InnerDir;\n\tint     AngleMin12, AngleMax12;\n};\nstatic const ImGuiResizeGripDef resize_grip_def[4] =\n{\n\t{ ImVec2(1, 1), ImVec2(-1, -1), 0, 3 },  // Lower-right\n\t{ ImVec2(0, 1), ImVec2(+1, -1), 3, 6 },  // Lower-left\n\t{ ImVec2(0, 0), ImVec2(+1, +1), 6, 9 },  // Upper-left (Unused)\n\t{ ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }  // Upper-right (Unused)\n};\n\n// Data for resizing from borders\nstruct ImGuiResizeBorderDef\n{\n\tImVec2 InnerDir;\n\tImVec2 SegmentN1, SegmentN2;\n\tfloat  OuterAngle;\n};\nstatic const ImGuiResizeBorderDef resize_border_def[4] =\n{\n\t{ ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left\n\t{ ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right\n\t{ ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up\n\t{ ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }  // Down\n};\n\nstatic ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)\n{\n\tImRect rect = window->Rect();\n\tif (thickness == 0.0f)\n\t\trect.Max -= ImVec2(1, 1);\n\tif (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }\n\tif (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }\n\tif (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }\n\tif (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }\n\tIM_ASSERT(0);\n\treturn ImRect();\n}\n\n// 0..3: corners (Lower-right, Lower-left, Unused, Unused)\nImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n)\n{\n\tIM_ASSERT(n >= 0 && n < 4);\n\tImGuiID id = window->ID;\n\tid = ImHashStr(\"#RESIZE\", 0, id);\n\tid = ImHashData(&n, sizeof(int), id);\n\treturn id;\n}\n\n// Borders (Left, Right, Up, Down)\nImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir)\n{\n\tIM_ASSERT(dir >= 0 && dir < 4);\n\tint n = (int)dir + 4;\n\tImGuiID id = window->ID;\n\tid = ImHashStr(\"#RESIZE\", 0, id);\n\tid = ImHashData(&n, sizeof(int), id);\n\treturn id;\n}\n\n// Handle resize for: Resize Grips, Borders, Gamepad\n// Return true when using auto-fit (double-click on resize grip)\nstatic bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindowFlags flags = window->Flags;\n\n\tif ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)\n\t\treturn false;\n\tif (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window.\n\t\treturn false;\n\n\tbool ret_auto_fit = false;\n\tconst int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;\n\tconst float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));\n\tconst float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);\n\tconst float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;\n\n\tImRect clamp_rect = visibility_rect;\n\tconst bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar);\n\tif (window_move_from_title_bar)\n\t\tclamp_rect.Min.y -= window->TitleBarHeight();\n\n\tImVec2 pos_target(FLT_MAX, FLT_MAX);\n\tImVec2 size_target(FLT_MAX, FLT_MAX);\n\n\t// Resize grips and borders are on layer 1\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Menu;\n\n\t// Manual resize grips\n\tPushID(\"#RESIZE\");\n\tfor (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)\n\t{\n\t\tconst ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];\n\t\tconst ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);\n\n\t\t// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window\n\t\tbool hovered, held;\n\t\tImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);\n\t\tif (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);\n\t\tif (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);\n\t\tImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()\n\t\tItemAdd(resize_rect, resize_grip_id, NULL, ImGuiItemFlags_NoNav);\n\t\tButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);\n\t\t//GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));\n\t\tif (hovered || held)\n\t\t\tg.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;\n\n\t\tif (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0)\n\t\t{\n\t\t\t// Manual auto-fit when double-clicking\n\t\t\tsize_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);\n\t\t\tret_auto_fit = true;\n\t\t\tClearActiveID();\n\t\t}\n\t\telse if (held)\n\t\t{\n\t\t\t// Resize from any of the four corners\n\t\t\t// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position\n\t\t\tImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? clamp_rect.Min.x : -FLT_MAX, (def.CornerPosN.y == 1.0f || (def.CornerPosN.y == 0.0f && window_move_from_title_bar)) ? clamp_rect.Min.y : -FLT_MAX);\n\t\t\tImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX);\n\t\t\tImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip\n\t\t\tcorner_target = ImClamp(corner_target, clamp_min, clamp_max);\n\t\t\tCalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);\n\t\t}\n\n\t\t// Only lower-left grip is visible before hovering/activating\n\t\tif (resize_grip_n == 0 || held || hovered)\n\t\t\tresize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);\n\t}\n\tfor (int border_n = 0; border_n < resize_border_count; border_n++)\n\t{\n\t\tconst ImGuiResizeBorderDef& def = resize_border_def[border_n];\n\t\tconst ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;\n\n\t\tbool hovered, held;\n\t\tImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);\n\t\tImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()\n\t\tItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav);\n\t\tButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);\n\t\t//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));\n\t\tif ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)\n\t\t{\n\t\t\tg.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;\n\t\t\tif (held)\n\t\t\t\t*border_held = border_n;\n\t\t}\n\t\tif (held)\n\t\t{\n\t\t\tImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX);\n\t\t\tImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX);\n\t\t\tImVec2 border_target = window->Pos;\n\t\t\tborder_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;\n\t\t\tborder_target = ImClamp(border_target, clamp_min, clamp_max);\n\t\t\tCalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);\n\t\t}\n\t}\n\tPopID();\n\n\t// Restore nav layer\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Main;\n\n\t// Navigation resize (keyboard/gamepad)\n\t// FIXME: This cannot be moved to NavUpdateWindowing() because CalcWindowSizeAfterConstraint() need to callback into user.\n\t// Not even sure the callback works here.\n\tif (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)\n\t{\n\t\tImVec2 nav_resize_dir;\n\t\tif (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift)\n\t\t\tnav_resize_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow);\n\t\tif (g.NavInputSource == ImGuiInputSource_Gamepad)\n\t\t\tnav_resize_dir = GetKeyMagnitude2d(ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown);\n\t\tif (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f)\n\t\t{\n\t\t\tconst float NAV_RESIZE_SPEED = 600.0f;\n\t\t\tconst float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y);\n\t\t\tg.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step;\n\t\t\tg.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size\n\t\t\tg.NavWindowingToggleLayer = false;\n\t\t\tg.NavDisableMouseHover = true;\n\t\t\tresize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);\n\t\t\tImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaSize);\n\t\t\tif (accum_floored.x != 0.0f || accum_floored.y != 0.0f)\n\t\t\t{\n\t\t\t\t// FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.\n\t\t\t\tsize_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + accum_floored);\n\t\t\t\tg.NavWindowingAccumDeltaSize -= accum_floored;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply back modified position/size to window\n\tif (size_target.x != FLT_MAX)\n\t{\n\t\twindow->SizeFull = size_target;\n\t\tMarkIniSettingsDirty(window);\n\t}\n\tif (pos_target.x != FLT_MAX)\n\t{\n\t\twindow->Pos = ImFloor(pos_target);\n\t\tMarkIniSettingsDirty(window);\n\t}\n\n\twindow->Size = window->SizeFull;\n\treturn ret_auto_fit;\n}\n\nstatic inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect)\n{\n\tImGuiContext& g = *GImGui;\n\tImVec2 size_for_clamping = window->Size;\n\tif (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))\n\t\tsize_for_clamping.y = window->TitleBarHeight();\n\twindow->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);\n}\n\nstatic void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tfloat rounding = window->WindowRounding;\n\tfloat border_size = window->WindowBorderSize;\n\tif (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))\n\t\twindow->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);\n\n\tint border_held = window->ResizeBorderHeld;\n\tif (border_held != -1)\n\t{\n\t\tconst ImGuiResizeBorderDef& def = resize_border_def[border_held];\n\t\tImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);\n\t\twindow->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);\n\t\twindow->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);\n\t\twindow->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual\n\t}\n\tif (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))\n\t{\n\t\tfloat y = window->Pos.y + window->TitleBarHeight() - 1;\n\t\twindow->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize);\n\t}\n}\n\n// Draw background and borders\n// Draw and handle scrollbars\nvoid ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiStyle& style = g.Style;\n\tImGuiWindowFlags flags = window->Flags;\n\n\t// Ensure that ScrollBar doesn't read last frame's SkipItems\n\tIM_ASSERT(window->BeginCount == 0);\n\twindow->SkipItems = false;\n\n\t// Draw window + handle manual resize\n\t// As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame.\n\tconst float window_rounding = window->WindowRounding;\n\tconst float window_border_size = window->WindowBorderSize;\n\tif (window->Collapsed)\n\t{\n\t\t// Title bar only\n\t\tconst float backup_border_size = style.FrameBorderSize;\n\t\tg.Style.FrameBorderSize = window->WindowBorderSize;\n\t\tImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);\n\t\tRenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);\n\t\tg.Style.FrameBorderSize = backup_border_size;\n\t}\n\telse\n\t{\n\t\t// Window background\n\t\tif (!(flags & ImGuiWindowFlags_NoBackground))\n\t\t{\n\t\t\tImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window));\n\t\t\tbool override_alpha = false;\n\t\t\tfloat alpha = 1.0f;\n\t\t\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)\n\t\t\t{\n\t\t\t\talpha = g.NextWindowData.BgAlphaVal;\n\t\t\t\toverride_alpha = true;\n\t\t\t}\n\t\t\tif (override_alpha)\n\t\t\t\tbg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);\n\t\t\twindow->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);\n\t\t}\n\n\t\t// Title bar\n\t\tif (!(flags & ImGuiWindowFlags_NoTitleBar))\n\t\t{\n\t\t\tImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);\n\t\t\twindow->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop);\n\t\t}\n\n\t\t// Menu bar\n\t\tif (flags & ImGuiWindowFlags_MenuBar)\n\t\t{\n\t\t\tImRect menu_bar_rect = window->MenuBarRect();\n\t\t\tmenu_bar_rect.ClipWith(window->Rect());  // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.\n\t\t\twindow->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);\n\t\t\tif (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)\n\t\t\t\twindow->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);\n\t\t}\n\n\t\t// Scrollbars\n\t\tif (window->ScrollbarX)\n\t\t\tScrollbar(ImGuiAxis_X);\n\t\tif (window->ScrollbarY)\n\t\t\tScrollbar(ImGuiAxis_Y);\n\n\t\t// Render resize grips (after their input handling so we don't have a frame of latency)\n\t\tif (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize))\n\t\t{\n\t\t\tfor (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)\n\t\t\t{\n\t\t\t\tconst ImU32 col = resize_grip_col[resize_grip_n];\n\t\t\t\tif ((col & IM_COL32_A_MASK) == 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tconst ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];\n\t\t\t\tconst ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);\n\t\t\t\twindow->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));\n\t\t\t\twindow->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));\n\t\t\t\twindow->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);\n\t\t\t\twindow->DrawList->PathFillConvex(col);\n\t\t\t}\n\t\t}\n\n\t\t// Borders\n\t\tif (handle_borders_and_resize_grips)\n\t\t\tRenderWindowOuterBorders(window);\n\t}\n}\n\n// Render title text, collapse button, close button\nvoid ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiStyle& style = g.Style;\n\tImGuiWindowFlags flags = window->Flags;\n\n\tconst bool has_close_button = (p_open != NULL);\n\tconst bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);\n\n\t// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)\n\t// FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref?\n\tconst ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;\n\tg.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Menu;\n\n\t// Layout buttons\n\t// FIXME: Would be nice to generalize the subtleties expressed here into reusable code.\n\tfloat pad_l = style.FramePadding.x;\n\tfloat pad_r = style.FramePadding.x;\n\tfloat button_sz = g.FontSize;\n\tImVec2 close_button_pos;\n\tImVec2 collapse_button_pos;\n\tif (has_close_button)\n\t{\n\t\tclose_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);\n\t\tpad_r += button_sz + style.ItemInnerSpacing.x;\n\t}\n\tif (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)\n\t{\n\t\tcollapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);\n\t\tpad_r += button_sz + style.ItemInnerSpacing.x;\n\t}\n\tif (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)\n\t{\n\t\tcollapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y);\n\t\tpad_l += button_sz + style.ItemInnerSpacing.x;\n\t}\n\n\t// Collapse button (submitting first so it gets priority when choosing a navigation init fallback)\n\tif (has_collapse_button)\n\t\tif (CollapseButton(window->GetID(\"#COLLAPSE\"), collapse_button_pos))\n\t\t\twindow->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function\n\n\t// Close button\n\tif (has_close_button)\n\t\tif (CloseButton(window->GetID(\"#CLOSE\"), close_button_pos))\n\t\t\t*p_open = false;\n\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Main;\n\tg.CurrentItemFlags = item_flags_backup;\n\n\t// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional \"unsaved document\" marker)\n\t// FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..\n\tconst float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f;\n\tconst ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);\n\n\t// As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,\n\t// while uncentered title text will still reach edges correctly.\n\tif (pad_l > style.FramePadding.x)\n\t\tpad_l += g.Style.ItemInnerSpacing.x;\n\tif (pad_r > style.FramePadding.x)\n\t\tpad_r += g.Style.ItemInnerSpacing.x;\n\tif (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)\n\t{\n\t\tfloat centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center\n\t\tfloat pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);\n\t\tpad_l = ImMax(pad_l, pad_extend * centerness);\n\t\tpad_r = ImMax(pad_r, pad_extend * centerness);\n\t}\n\n\tImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);\n\tImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y);\n\tif (flags & ImGuiWindowFlags_UnsavedDocument)\n\t{\n\t\tImVec2 marker_pos;\n\t\tmarker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x);\n\t\tmarker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f;\n\t\tif (marker_pos.x > layout_r.Min.x)\n\t\t{\n\t\t\tRenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text));\n\t\t\tclip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f));\n\t\t}\n\t}\n\t//if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]\n\t//if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]\n\tRenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);\n}\n\nvoid ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)\n{\n\twindow->ParentWindow = parent_window;\n\twindow->RootWindow = window->RootWindowPopupTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;\n\tif (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))\n\t\twindow->RootWindow = parent_window->RootWindow;\n\tif (parent_window && (flags & ImGuiWindowFlags_Popup))\n\t\twindow->RootWindowPopupTree = parent_window->RootWindowPopupTree;\n\tif (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))\n\t\twindow->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;\n\twhile (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)\n\t{\n\t\tIM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);\n\t\twindow->RootWindowForNav = window->RootWindowForNav->ParentWindow;\n\t}\n}\n\n// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)\n// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.\n// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.\n// - WindowA            // FindBlockingModal() returns Modal1\n//   - WindowB          //                  .. returns Modal1\n//   - Modal1           //                  .. returns Modal2\n//      - WindowC       //                  .. returns Modal2\n//          - WindowD   //                  .. returns Modal2\n//          - Modal2    //                  .. returns Modal2\n//            - WindowE //                  .. returns NULL\n// Notes:\n// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL.\n//   Only difference is here we check for ->Active/WasActive but it may be unecessary.\nImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.OpenPopupStack.Size <= 0)\n\t\treturn NULL;\n\n\t// Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.\n\tfor (ImGuiPopupData& popup_data : g.OpenPopupStack)\n\t{\n\t\tImGuiWindow* popup_window = popup_data.Window;\n\t\tif (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))\n\t\t\tcontinue;\n\t\tif (!popup_window->Active && !popup_window->WasActive)      // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.\n\t\t\tcontinue;\n\t\tif (window == NULL)                                         // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click.\n\t\t\treturn popup_window;\n\t\tif (IsWindowWithinBeginStackOf(window, popup_window))       // Window may be over modal\n\t\t\tcontinue;\n\t\treturn popup_window;                                        // Place window right below first block modal\n\t}\n\treturn NULL;\n}\n\n// Push a new Dear ImGui window to add widgets to.\n// - A default window called \"Debug\" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.\n// - Begin/End can be called multiple times during the frame with the same window name to append content.\n// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).\n//   You can use the \"##\" or \"###\" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.\n// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.\n// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.\nbool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tIM_ASSERT(name != NULL && name[0] != '\\0');     // Window name required\n\tIM_ASSERT(g.WithinFrameScope);                  // Forgot to call ImGui::NewFrame()\n\tIM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet\n\n\t// Find or create\n\tImGuiWindow* window = FindWindowByName(name);\n\tconst bool window_just_created = (window == NULL);\n\tif (window_just_created)\n\t\twindow = CreateNewWindow(name, flags);\n\n\t// Automatically disable manual moving/resizing when NoInputs is set\n\tif ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)\n\t\tflags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;\n\n\tif (flags & ImGuiWindowFlags_NavFlattened)\n\t\tIM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);\n\n\tconst int current_frame = g.FrameCount;\n\tconst bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);\n\twindow->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);\n\n\t// Update the Appearing flag\n\tbool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit \"Debug\" window would always toggle off->on\n\tif (flags & ImGuiWindowFlags_Popup)\n\t{\n\t\tImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];\n\t\twindow_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed\n\t\twindow_just_activated_by_user |= (window != popup_ref.Window);\n\t}\n\twindow->Appearing = window_just_activated_by_user;\n\tif (window->Appearing)\n\t\tSetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);\n\n\t// Update Flags, LastFrameActive, BeginOrderXXX fields\n\tif (first_begin_of_the_frame)\n\t{\n\t\tUpdateWindowInFocusOrderList(window, window_just_created, flags);\n\t\twindow->Flags = (ImGuiWindowFlags)flags;\n\t\twindow->LastFrameActive = current_frame;\n\t\twindow->LastTimeActive = (float)g.Time;\n\t\twindow->BeginOrderWithinParent = 0;\n\t\twindow->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);\n\t}\n\telse\n\t{\n\t\tflags = window->Flags;\n\t}\n\n\t// Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack\n\tImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;\n\tImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;\n\tIM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));\n\n\t// We allow window memory to be compacted so recreate the base stack when needed.\n\tif (window->IDStack.Size == 0)\n\t\twindow->IDStack.push_back(window->ID);\n\n\t// Add to stack\n\t// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()\n\tg.CurrentWindow = window;\n\tImGuiWindowStackData window_stack_data;\n\twindow_stack_data.Window = window;\n\twindow_stack_data.ParentLastItemDataBackup = g.LastItemData;\n\twindow_stack_data.StackSizesOnBegin.SetToContextState(&g);\n\tg.CurrentWindowStack.push_back(window_stack_data);\n\tif (flags & ImGuiWindowFlags_ChildMenu)\n\t\tg.BeginMenuCount++;\n\n\t// Update ->RootWindow and others pointers (before any possible call to FocusWindow)\n\tif (first_begin_of_the_frame)\n\t{\n\t\tUpdateWindowParentAndRootLinks(window, flags, parent_window);\n\t\twindow->ParentWindowInBeginStack = parent_window_in_stack;\n\t}\n\n\t// Add to focus scope stack\n\tPushFocusScope(window->ID);\n\twindow->NavRootFocusScopeId = g.CurrentFocusScopeId;\n\tg.CurrentWindow = NULL;\n\n\t// Add to popup stack\n\tif (flags & ImGuiWindowFlags_Popup)\n\t{\n\t\tImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];\n\t\tpopup_ref.Window = window;\n\t\tpopup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent;\n\t\tg.BeginPopupStack.push_back(popup_ref);\n\t\twindow->PopupId = popup_ref.PopupId;\n\t}\n\n\t// Process SetNextWindow***() calls\n\t// (FIXME: Consider splitting the HasXXX flags into X/Y components\n\tbool window_pos_set_by_api = false;\n\tbool window_size_x_set_by_api = false, window_size_y_set_by_api = false;\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)\n\t{\n\t\twindow_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;\n\t\tif (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)\n\t\t{\n\t\t\t// May be processed on the next frame if this is our first frame and we are measuring size\n\t\t\t// FIXME: Look into removing the branch so everything can go through this same code path for consistency.\n\t\t\twindow->SetWindowPosVal = g.NextWindowData.PosVal;\n\t\t\twindow->SetWindowPosPivot = g.NextWindowData.PosPivotVal;\n\t\t\twindow->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);\n\t\t}\n\t}\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)\n\t{\n\t\twindow_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);\n\t\twindow_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);\n\t\tSetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);\n\t}\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)\n\t{\n\t\tif (g.NextWindowData.ScrollVal.x >= 0.0f)\n\t\t{\n\t\t\twindow->ScrollTarget.x = g.NextWindowData.ScrollVal.x;\n\t\t\twindow->ScrollTargetCenterRatio.x = 0.0f;\n\t\t}\n\t\tif (g.NextWindowData.ScrollVal.y >= 0.0f)\n\t\t{\n\t\t\twindow->ScrollTarget.y = g.NextWindowData.ScrollVal.y;\n\t\t\twindow->ScrollTargetCenterRatio.y = 0.0f;\n\t\t}\n\t}\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)\n\t\twindow->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;\n\telse if (first_begin_of_the_frame)\n\t\twindow->ContentSizeExplicit = ImVec2(0.0f, 0.0f);\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)\n\t\tSetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)\n\t\tFocusWindow(window);\n\tif (window->Appearing)\n\t\tSetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);\n\n\t// When reusing window again multiple times a frame, just append content (don't need to setup again)\n\tif (first_begin_of_the_frame)\n\t{\n\t\t// Initialize\n\t\tconst bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)\n\t\tconst bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);\n\t\twindow->Active = true;\n\t\twindow->HasCloseButton = (p_open != NULL);\n\t\twindow->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);\n\t\twindow->IDStack.resize(1);\n\t\twindow->DrawList->_ResetForNewFrame();\n\t\twindow->DC.CurrentTableIdx = -1;\n\n\t\t// Restore buffer capacity when woken from a compacted state, to avoid\n\t\tif (window->MemoryCompacted)\n\t\t\tGcAwakeTransientWindowBuffers(window);\n\n\t\t// Update stored window name when it changes (which can _only_ happen with the \"###\" operator, so the ID would stay unchanged).\n\t\t// The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.\n\t\tbool window_title_visible_elsewhere = false;\n\t\tif (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB\n\t\t\twindow_title_visible_elsewhere = true;\n\t\tif (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)\n\t\t{\n\t\t\tsize_t buf_len = (size_t)window->NameBufLen;\n\t\t\twindow->Name = ImStrdupcpy(window->Name, &buf_len, name);\n\t\t\twindow->NameBufLen = (int)buf_len;\n\t\t}\n\n\t\t// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS\n\n\t\t// Update contents size from last frame for auto-fitting (or use explicit size)\n\t\tCalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);\n\t\tif (window->HiddenFramesCanSkipItems > 0)\n\t\t\twindow->HiddenFramesCanSkipItems--;\n\t\tif (window->HiddenFramesCannotSkipItems > 0)\n\t\t\twindow->HiddenFramesCannotSkipItems--;\n\t\tif (window->HiddenFramesForRenderOnly > 0)\n\t\t\twindow->HiddenFramesForRenderOnly--;\n\n\t\t// Hide new windows for one frame until they calculate their size\n\t\tif (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))\n\t\t\twindow->HiddenFramesCannotSkipItems = 1;\n\n\t\t// Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)\n\t\t// We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.\n\t\tif (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)\n\t\t{\n\t\t\twindow->HiddenFramesCannotSkipItems = 1;\n\t\t\tif (flags & ImGuiWindowFlags_AlwaysAutoResize)\n\t\t\t{\n\t\t\t\tif (!window_size_x_set_by_api)\n\t\t\t\t\twindow->Size.x = window->SizeFull.x = 0.f;\n\t\t\t\tif (!window_size_y_set_by_api)\n\t\t\t\t\twindow->Size.y = window->SizeFull.y = 0.f;\n\t\t\t\twindow->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f);\n\t\t\t}\n\t\t}\n\n\t\t// SELECT VIEWPORT\n\t\t// FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)\n\n\t\tImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();\n\t\tSetWindowViewport(window, viewport);\n\t\tSetCurrentWindow(window);\n\n\t\t// LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)\n\n\t\tif (flags & ImGuiWindowFlags_ChildWindow)\n\t\t\twindow->WindowBorderSize = style.ChildBorderSize;\n\t\telse\n\t\t\twindow->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;\n\t\twindow->WindowPadding = style.WindowPadding;\n\t\tif ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)\n\t\t\twindow->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);\n\n\t\t// Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.\n\t\twindow->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);\n\t\twindow->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;\n\n\t\tbool use_current_size_for_scrollbar_x = window_just_created;\n\t\tbool use_current_size_for_scrollbar_y = window_just_created;\n\n\t\t// Collapse window by double-clicking on title bar\n\t\t// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing\n\t\tif (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))\n\t\t{\n\t\t\t// We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.\n\t\t\tImRect title_bar_rect = window->TitleBarRect();\n\t\t\tif (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2)\n\t\t\t\twindow->WantCollapseToggle = true;\n\t\t\tif (window->WantCollapseToggle)\n\t\t\t{\n\t\t\t\twindow->Collapsed = !window->Collapsed;\n\t\t\t\tif (!window->Collapsed)\n\t\t\t\t\tuse_current_size_for_scrollbar_y = true;\n\t\t\t\tMarkIniSettingsDirty(window);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\twindow->Collapsed = false;\n\t\t}\n\t\twindow->WantCollapseToggle = false;\n\n\t\t// SIZE\n\n\t\t// Outer Decoration Sizes\n\t\t// (we need to clear ScrollbarSize immediatly as CalcWindowAutoFitSize() needs it and can be called from other locations).\n\t\tconst ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes;\n\t\twindow->DecoOuterSizeX1 = 0.0f;\n\t\twindow->DecoOuterSizeX2 = 0.0f;\n\t\twindow->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight();\n\t\twindow->DecoOuterSizeY2 = 0.0f;\n\t\twindow->ScrollbarSizes = ImVec2(0.0f, 0.0f);\n\n\t\t// Calculate auto-fit size, handle automatic resize\n\t\tconst ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal);\n\t\tif ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)\n\t\t{\n\t\t\t// Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.\n\t\t\tif (!window_size_x_set_by_api)\n\t\t\t{\n\t\t\t\twindow->SizeFull.x = size_auto_fit.x;\n\t\t\t\tuse_current_size_for_scrollbar_x = true;\n\t\t\t}\n\t\t\tif (!window_size_y_set_by_api)\n\t\t\t{\n\t\t\t\twindow->SizeFull.y = size_auto_fit.y;\n\t\t\t\tuse_current_size_for_scrollbar_y = true;\n\t\t\t}\n\t\t}\n\t\telse if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)\n\t\t{\n\t\t\t// Auto-fit may only grow window during the first few frames\n\t\t\t// We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.\n\t\t\tif (!window_size_x_set_by_api && window->AutoFitFramesX > 0)\n\t\t\t{\n\t\t\t\twindow->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;\n\t\t\t\tuse_current_size_for_scrollbar_x = true;\n\t\t\t}\n\t\t\tif (!window_size_y_set_by_api && window->AutoFitFramesY > 0)\n\t\t\t{\n\t\t\t\twindow->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;\n\t\t\t\tuse_current_size_for_scrollbar_y = true;\n\t\t\t}\n\t\t\tif (!window->Collapsed)\n\t\t\t\tMarkIniSettingsDirty(window);\n\t\t}\n\n\t\t// Apply minimum/maximum window size constraints and final size\n\t\twindow->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);\n\t\twindow->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;\n\n\t\t// POSITION\n\n\t\t// Popup latch its initial position, will position itself when it appears next frame\n\t\tif (window_just_activated_by_user)\n\t\t{\n\t\t\twindow->AutoPosLastDirection = ImGuiDir_None;\n\t\t\tif ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()\n\t\t\t\twindow->Pos = g.BeginPopupStack.back().OpenPopupPos;\n\t\t}\n\n\t\t// Position child window\n\t\tif (flags & ImGuiWindowFlags_ChildWindow)\n\t\t{\n\t\t\tIM_ASSERT(parent_window && parent_window->Active);\n\t\t\twindow->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;\n\t\t\tparent_window->DC.ChildWindows.push_back(window);\n\t\t\tif (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)\n\t\t\t\twindow->Pos = parent_window->DC.CursorPos;\n\t\t}\n\n\t\tconst bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);\n\t\tif (window_pos_with_pivot)\n\t\t\tSetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)\n\t\telse if ((flags & ImGuiWindowFlags_ChildMenu) != 0)\n\t\t\twindow->Pos = FindBestWindowPosForPopup(window);\n\t\telse if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)\n\t\t\twindow->Pos = FindBestWindowPosForPopup(window);\n\t\telse if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)\n\t\t\twindow->Pos = FindBestWindowPosForPopup(window);\n\n\t\t// Calculate the range of allowed position for that window (to be movable and visible past safe area padding)\n\t\t// When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.\n\t\tImRect viewport_rect(viewport->GetMainRect());\n\t\tImRect viewport_work_rect(viewport->GetWorkRect());\n\t\tImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);\n\t\tImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding);\n\n\t\t// Clamp position/size so window stays visible within its viewport or monitor\n\t\t// Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.\n\t\tif (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow))\n\t\t\tif (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)\n\t\t\t\tClampWindowPos(window, visibility_rect);\n\t\twindow->Pos = ImFloor(window->Pos);\n\n\t\t// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)\n\t\t// Large values tend to lead to variety of artifacts and are not recommended.\n\t\twindow->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;\n\n\t\t// For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.\n\t\t//if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))\n\t\t//    window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);\n\n\t\t// Apply window focus (new and reactivated windows are moved to front)\n\t\tbool want_focus = false;\n\t\tif (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))\n\t\t{\n\t\t\tif (flags & ImGuiWindowFlags_Popup)\n\t\t\t\twant_focus = true;\n\t\t\telse if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)\n\t\t\t\twant_focus = true;\n\t\t}\n\n\t\t// [Test Engine] Register whole window in the item system (before submitting further decorations)\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\t\tif (g.TestEngineHookItems)\n\t\t{\n\t\t\tIM_ASSERT(window->IDStack.Size == 1);\n\t\t\twindow->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself.\n\t\t\tIMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL);\n\t\t\tIMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0);\n\t\t\twindow->IDStack.Size = 1;\n\t\t}\n#endif\n\n\t\t// Handle manual resize: Resize Grips, Borders, Gamepad\n\t\tint border_held = -1;\n\t\tImU32 resize_grip_col[4] = {};\n\t\tconst int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.\n\t\tconst float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));\n\t\tif (!window->Collapsed)\n\t\t\tif (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))\n\t\t\t\tuse_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;\n\t\twindow->ResizeBorderHeld = (signed char)border_held;\n\n\t\t// SCROLLBAR VISIBILITY\n\n\t\t// Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).\n\t\tif (!window->Collapsed)\n\t\t{\n\t\t\t// When reading the current size we need to read it after size constraints have been applied.\n\t\t\t// Intentionally use previous frame values for InnerRect and ScrollbarSizes.\n\t\t\t// And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet.\n\t\t\tImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2));\n\t\t\tImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame;\n\t\t\tImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;\n\t\t\tfloat size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;\n\t\t\tfloat size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;\n\t\t\t//bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?\n\t\t\twindow->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));\n\t\t\twindow->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));\n\t\t\tif (window->ScrollbarX && !window->ScrollbarY)\n\t\t\t\twindow->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);\n\t\t\twindow->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);\n\n\t\t\t// Amend the partially filled window->DecorationXXX values.\n\t\t\twindow->DecoOuterSizeX2 += window->ScrollbarSizes.x;\n\t\t\twindow->DecoOuterSizeY2 += window->ScrollbarSizes.y;\n\t\t}\n\n\t\t// UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)\n\t\t// Update various regions. Variables they depend on should be set above in this function.\n\t\t// We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.\n\n\t\t// Outer rectangle\n\t\t// Not affected by window border size. Used by:\n\t\t// - FindHoveredWindow() (w/ extra padding when border resize is enabled)\n\t\t// - Begin() initial clipping rect for drawing window background and borders.\n\t\t// - Begin() clipping whole child\n\t\tconst ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;\n\t\tconst ImRect outer_rect = window->Rect();\n\t\tconst ImRect title_bar_rect = window->TitleBarRect();\n\t\twindow->OuterRectClipped = outer_rect;\n\t\twindow->OuterRectClipped.ClipWith(host_rect);\n\n\t\t// Inner rectangle\n\t\t// Not affected by window border size. Used by:\n\t\t// - InnerClipRect\n\t\t// - ScrollToRectEx()\n\t\t// - NavUpdatePageUpPageDown()\n\t\t// - Scrollbar()\n\t\twindow->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1;\n\t\twindow->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1;\n\t\twindow->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2;\n\t\twindow->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2;\n\n\t\t// Inner clipping rectangle.\n\t\t// Will extend a little bit outside the normal work region.\n\t\t// This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.\n\t\t// Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.\n\t\t// Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.\n\t\t// Affected by window/frame border size. Used by:\n\t\t// - Begin() initial clip rect\n\t\tfloat top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);\n\t\twindow->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));\n\t\twindow->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);\n\t\twindow->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));\n\t\twindow->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);\n\t\twindow->InnerClipRect.ClipWithFull(host_rect);\n\n\t\t// Default item width. Make it proportional to window size if window manually resizes\n\t\tif (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))\n\t\t\twindow->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);\n\t\telse\n\t\t\twindow->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);\n\n\t\t// SCROLLING\n\n\t\t// Lock down maximum scrolling\n\t\t// The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate\n\t\t// for right/bottom aligned items without creating a scrollbar.\n\t\twindow->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());\n\t\twindow->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());\n\n\t\t// Apply scrolling\n\t\twindow->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);\n\t\twindow->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);\n\t\twindow->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f;\n\n\t\t// DRAWING\n\n\t\t// Setup draw list and outer clipping rectangle\n\t\tIM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);\n\t\twindow->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);\n\t\tPushClipRect(host_rect.Min, host_rect.Max, false);\n\n\t\t// Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)\n\t\t// When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.\n\t\t// FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)\n\t\t{\n\t\t\tbool render_decorations_in_parent = false;\n\t\t\tif ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)\n\t\t\t{\n\t\t\t\t// - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here)\n\t\t\t\t// - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs\n\t\t\t\tImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL;\n\t\t\t\tbool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false;\n\t\t\t\tbool parent_is_empty = (parent_window->DrawList->VtxBuffer.Size == 0);\n\t\t\t\tif (window->DrawList->CmdBuffer.back().ElemCount == 0 && !parent_is_empty && !previous_child_overlapping)\n\t\t\t\t\trender_decorations_in_parent = true;\n\t\t\t}\n\t\t\tif (render_decorations_in_parent)\n\t\t\t\twindow->DrawList = parent_window->DrawList;\n\n\t\t\t// Handle title bar, scrollbar, resize grips and resize borders\n\t\t\tconst ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;\n\t\t\tconst bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);\n\t\t\tconst bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch.\n\t\t\tRenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size);\n\n\t\t\tif (render_decorations_in_parent)\n\t\t\t\twindow->DrawList = &window->DrawListInst;\n\t\t}\n\n\t\t// UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)\n\n\t\t// Work rectangle.\n\t\t// Affected by window padding and border size. Used by:\n\t\t// - Columns() for right-most edge\n\t\t// - TreeNode(), CollapsingHeader() for right-most edge\n\t\t// - BeginTabBar() for right-most edge\n\t\tconst bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);\n\t\tconst bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);\n\t\tconst float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));\n\t\tconst float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));\n\t\twindow->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));\n\t\twindow->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));\n\t\twindow->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;\n\t\twindow->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;\n\t\twindow->ParentWorkRect = window->WorkRect;\n\n\t\t// [LEGACY] Content Region\n\t\t// FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.\n\t\t// Unless explicit content size is specified by user, this currently represent the region leading to no scrolling.\n\t\t// Used by:\n\t\t// - Mouse wheel scrolling + many other things\n\t\twindow->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1;\n\t\twindow->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1;\n\t\twindow->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));\n\t\twindow->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));\n\n\t\t// Setup drawing context\n\t\t// (NB: That term \"drawing context / DC\" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)\n\t\twindow->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x;\n\t\twindow->DC.GroupOffset.x = 0.0f;\n\t\twindow->DC.ColumnsOffset.x = 0.0f;\n\n\t\t// Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount.\n\t\t// This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64.\n\t\tdouble start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x;\n\t\tdouble start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1;\n\t\twindow->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y);\n\t\twindow->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y));\n\t\twindow->DC.CursorPos = window->DC.CursorStartPos;\n\t\twindow->DC.CursorPosPrevLine = window->DC.CursorPos;\n\t\twindow->DC.CursorMaxPos = window->DC.CursorStartPos;\n\t\twindow->DC.IdealMaxPos = window->DC.CursorStartPos;\n\t\twindow->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);\n\t\twindow->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;\n\t\twindow->DC.IsSameLine = window->DC.IsSetPos = false;\n\n\t\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Main;\n\t\twindow->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;\n\t\twindow->DC.NavLayersActiveMaskNext = 0x00;\n\t\twindow->DC.NavIsScrollPushableX = true;\n\t\twindow->DC.NavHideHighlightOneFrame = false;\n\t\twindow->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f);\n\n\t\twindow->DC.MenuBarAppending = false;\n\t\twindow->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);\n\t\twindow->DC.TreeDepth = 0;\n\t\twindow->DC.TreeJumpToParentOnPopMask = 0x00;\n\t\twindow->DC.ChildWindows.resize(0);\n\t\twindow->DC.StateStorage = &window->StateStorage;\n\t\twindow->DC.CurrentColumns = NULL;\n\t\twindow->DC.LayoutType = ImGuiLayoutType_Vertical;\n\t\twindow->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;\n\n\t\twindow->DC.ItemWidth = window->ItemWidthDefault;\n\t\twindow->DC.TextWrapPos = -1.0f; // disabled\n\t\twindow->DC.ItemWidthStack.resize(0);\n\t\twindow->DC.TextWrapPosStack.resize(0);\n\n\t\tif (window->AutoFitFramesX > 0)\n\t\t\twindow->AutoFitFramesX--;\n\t\tif (window->AutoFitFramesY > 0)\n\t\t\twindow->AutoFitFramesY--;\n\n\t\t// Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)\n\t\t// We ImGuiFocusRequestFlags_UnlessBelowModal to:\n\t\t// - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed.\n\t\t// - Position window behind the modal that is not a begin-parent of this window.\n\t\tif (want_focus)\n\t\t\tFocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal);\n\t\tif (want_focus && window == g.NavWindow)\n\t\t\tNavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls\n\n\t\t// Title bar\n\t\tif (!(flags & ImGuiWindowFlags_NoTitleBar))\n\t\t\tRenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open);\n\n\t\t// Clear hit test shape every frame\n\t\twindow->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;\n\n\t\t// Pressing CTRL+C while holding on a window copy its content to the clipboard\n\t\t// This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.\n\t\t// Maybe we can support CTRL+C on every element?\n\t\t/*\n\t\t//if (g.NavWindow == window && g.ActiveId == 0)\n\t\tif (g.ActiveId == window->MoveId)\n\t\t\tif (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C))\n\t\t\t\tLogToClipboard();\n\t\t*/\n\n\t\t// We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().\n\t\t// This is useful to allow creating context menus on title bar only, etc.\n\t\tSetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);\n\n\t\t// [DEBUG]\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\t\tif (g.DebugLocateId != 0 && (window->ID == g.DebugLocateId || window->MoveId == g.DebugLocateId))\n\t\t\tDebugLocateItemResolveWithLastItem();\n#endif\n\n\t\t// [Test Engine] Register title bar / tab with MoveId.\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\t\tif (!(window->Flags & ImGuiWindowFlags_NoTitleBar))\n\t\t\tIMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData);\n#endif\n\t}\n\telse\n\t{\n\t\t// Append\n\t\tSetCurrentWindow(window);\n\t}\n\n\tPushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);\n\n\t// Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default \"Debug\" window is unused)\n\twindow->WriteAccessed = false;\n\twindow->BeginCount++;\n\tg.NextWindowData.ClearFlags();\n\n\t// Update visibility\n\tif (first_begin_of_the_frame)\n\t{\n\t\tif (flags & ImGuiWindowFlags_ChildWindow)\n\t\t{\n\t\t\t// Child window can be out of sight and have \"negative\" clip windows.\n\t\t\t// Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).\n\t\t\tIM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);\n\t\t\tif (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow??\n\t\t\t{\n\t\t\t\tconst bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);\n\t\t\t\tif (!g.LogEnabled && !nav_request)\n\t\t\t\t\tif (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)\n\t\t\t\t\t\twindow->HiddenFramesCanSkipItems = 1;\n\t\t\t}\n\n\t\t\t// Hide along with parent or if parent is collapsed\n\t\t\tif (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))\n\t\t\t\twindow->HiddenFramesCanSkipItems = 1;\n\t\t\tif (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))\n\t\t\t\twindow->HiddenFramesCannotSkipItems = 1;\n\t\t}\n\n\t\t// Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)\n\t\tif (style.Alpha <= 0.0f)\n\t\t\twindow->HiddenFramesCanSkipItems = 1;\n\n\t\t// Update the Hidden flag\n\t\tbool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);\n\t\twindow->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0);\n\n\t\t// Disable inputs for requested number of frames\n\t\tif (window->DisableInputsFrames > 0)\n\t\t{\n\t\t\twindow->DisableInputsFrames--;\n\t\t\twindow->Flags |= ImGuiWindowFlags_NoInputs;\n\t\t}\n\n\t\t// Update the SkipItems flag, used to early out of all items functions (no layout required)\n\t\tbool skip_items = false;\n\t\tif (window->Collapsed || !window->Active || hidden_regular)\n\t\t\tif (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)\n\t\t\t\tskip_items = true;\n\t\twindow->SkipItems = skip_items;\n\t}\n\n\t// [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors.\n\t// (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing)\n\tif (!window->IsFallbackWindow && ((g.IO.ConfigDebugBeginReturnValueOnce && window_just_created) || (g.IO.ConfigDebugBeginReturnValueLoop && g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size)))\n\t{\n\t\tif (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; }\n\t\tif (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; }\n\t\treturn false;\n\t}\n\n\treturn !window->SkipItems;\n}\n\nvoid ImGui::End()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// Error checking: verify that user hasn't called End() too many times!\n\tif (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)\n\t{\n\t\tIM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, \"Calling End() too many times!\");\n\t\treturn;\n\t}\n\tIM_ASSERT(g.CurrentWindowStack.Size > 0);\n\n\t// Error checking: verify that user doesn't directly call End() on a child window.\n\tif (window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\tIM_ASSERT_USER_ERROR(g.WithinEndChild, \"Must call EndChild() and not End()!\");\n\n\t// Close anything that is open\n\tif (window->DC.CurrentColumns)\n\t\tEndColumns();\n\tPopClipRect();   // Inner window clip rectangle\n\tPopFocusScope();\n\n\t// Stop logging\n\tif (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging\n\t\tLogFinish();\n\n\tif (window->DC.IsSetPos)\n\t\tErrorCheckUsingSetCursorPosToExtendParentBoundaries();\n\n\t// Pop from window stack\n\tg.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;\n\tif (window->Flags & ImGuiWindowFlags_ChildMenu)\n\t\tg.BeginMenuCount--;\n\tif (window->Flags & ImGuiWindowFlags_Popup)\n\t\tg.BeginPopupStack.pop_back();\n\tg.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g);\n\tg.CurrentWindowStack.pop_back();\n\tSetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);\n}\n\nvoid ImGui::BringWindowToFocusFront(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(window == window->RootWindow);\n\n\tconst int cur_order = window->FocusOrder;\n\tIM_ASSERT(g.WindowsFocusOrder[cur_order] == window);\n\tif (g.WindowsFocusOrder.back() == window)\n\t\treturn;\n\n\tconst int new_order = g.WindowsFocusOrder.Size - 1;\n\tfor (int n = cur_order; n < new_order; n++)\n\t{\n\t\tg.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];\n\t\tg.WindowsFocusOrder[n]->FocusOrder--;\n\t\tIM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);\n\t}\n\tg.WindowsFocusOrder[new_order] = window;\n\twindow->FocusOrder = (short)new_order;\n}\n\nvoid ImGui::BringWindowToDisplayFront(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* current_front_window = g.Windows.back();\n\tif (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)\n\t\treturn;\n\tfor (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window\n\t\tif (g.Windows[i] == window)\n\t\t{\n\t\t\tmemmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));\n\t\t\tg.Windows[g.Windows.Size - 1] = window;\n\t\t\tbreak;\n\t\t}\n}\n\nvoid ImGui::BringWindowToDisplayBack(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.Windows[0] == window)\n\t\treturn;\n\tfor (int i = 0; i < g.Windows.Size; i++)\n\t\tif (g.Windows[i] == window)\n\t\t{\n\t\t\tmemmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));\n\t\t\tg.Windows[0] = window;\n\t\t\tbreak;\n\t\t}\n}\n\nvoid ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window)\n{\n\tIM_ASSERT(window != NULL && behind_window != NULL);\n\tImGuiContext& g = *GImGui;\n\twindow = window->RootWindow;\n\tbehind_window = behind_window->RootWindow;\n\tint pos_wnd = FindWindowDisplayIndex(window);\n\tint pos_beh = FindWindowDisplayIndex(behind_window);\n\tif (pos_wnd < pos_beh)\n\t{\n\t\tsize_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*);\n\t\tmemmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes);\n\t\tg.Windows[pos_beh - 1] = window;\n\t}\n\telse\n\t{\n\t\tsize_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*);\n\t\tmemmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes);\n\t\tg.Windows[pos_beh] = window;\n\t}\n}\n\nint ImGui::FindWindowDisplayIndex(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.Windows.index_from_ptr(g.Windows.find(window));\n}\n\n// Moving window to front of display and set focus (which happens to be back of our sorted list)\nvoid ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Modal check?\n\tif ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case.\n\t\tif (ImGuiWindow* blocking_modal = FindBlockingModal(window))\n\t\t{\n\t\t\tIMGUI_DEBUG_LOG_FOCUS(\"[focus] FocusWindow(\\\"%s\\\", UnlessBelowModal): prevented by \\\"%s\\\".\\n\", window ? window->Name : \"<NULL>\", blocking_modal->Name);\n\t\t\tif (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)\n\t\t\t\tBringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal.\n\t\t\treturn;\n\t\t}\n\n\t// Find last focused child (if any) and focus it instead.\n\tif ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL)\n\t\twindow = NavRestoreLastChildNavWindow(window);\n\n\t// Apply focus\n\tif (g.NavWindow != window)\n\t{\n\t\tSetNavWindow(window);\n\t\tif (window && g.NavDisableMouseHover)\n\t\t\tg.NavMousePosDirty = true;\n\t\tg.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId\n\t\tg.NavLayer = ImGuiNavLayer_Main;\n\t\tg.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0;\n\t\tg.NavIdIsAlive = false;\n\n\t\t// Close popups if any\n\t\tClosePopupsOverWindow(window, false);\n\t}\n\n\t// Move the root window to the top of the pile\n\tIM_ASSERT(window == NULL || window->RootWindow != NULL);\n\tImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop\n\tImGuiWindow* display_front_window = window ? window->RootWindow : NULL;\n\n\t// Steal active widgets. Some of the cases it triggers includes:\n\t// - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.\n\t// - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)\n\tif (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)\n\t\tif (!g.ActiveIdNoClearOnFocusLoss)\n\t\t\tClearActiveID();\n\n\t// Passing NULL allow to disable keyboard focus\n\tif (!window)\n\t\treturn;\n\n\t// Bring to front\n\tBringWindowToFocusFront(focus_front_window);\n\tif (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)\n\t\tBringWindowToDisplayFront(display_front_window);\n}\n\nvoid ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_UNUSED(filter_viewport); // Unused in master branch.\n\tint start_idx = g.WindowsFocusOrder.Size - 1;\n\tif (under_this_window != NULL)\n\t{\n\t\t// Aim at root window behind us, if we are in a child window that's our own root (see #4640)\n\t\tint offset = -1;\n\t\twhile (under_this_window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\t{\n\t\t\tunder_this_window = under_this_window->ParentWindow;\n\t\t\toffset = 0;\n\t\t}\n\t\tstart_idx = FindWindowFocusIndex(under_this_window) + offset;\n\t}\n\tfor (int i = start_idx; i >= 0; i--)\n\t{\n\t\t// We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.\n\t\tImGuiWindow* window = g.WindowsFocusOrder[i];\n\t\tIM_ASSERT(window == window->RootWindow);\n\t\tif (window == ignore_window || !window->WasActive)\n\t\t\tcontinue;\n\t\tif ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))\n\t\t{\n\t\t\tFocusWindow(window, flags);\n\t\t\treturn;\n\t\t}\n\t}\n\tFocusWindow(NULL, flags);\n}\n\n// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.\nvoid ImGui::SetCurrentFont(ImFont* font)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?\n\tIM_ASSERT(font->Scale > 0.0f);\n\tg.Font = font;\n\tg.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);\n\tg.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;\n\n\tImFontAtlas* atlas = g.Font->ContainerAtlas;\n\tg.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;\n\tg.DrawListSharedData.TexUvLines = atlas->TexUvLines;\n\tg.DrawListSharedData.Font = g.Font;\n\tg.DrawListSharedData.FontSize = g.FontSize;\n}\n\nvoid ImGui::PushFont(ImFont* font)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!font)\n\t\tfont = GetDefaultFont();\n\tSetCurrentFont(font);\n\tg.FontStack.push_back(font);\n\tg.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);\n}\n\nvoid  ImGui::PopFont()\n{\n\tImGuiContext& g = *GImGui;\n\tg.CurrentWindow->DrawList->PopTextureID();\n\tg.FontStack.pop_back();\n\tSetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());\n}\n\nvoid ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiItemFlags item_flags = g.CurrentItemFlags;\n\tIM_ASSERT(item_flags == g.ItemFlagsStack.back());\n\tif (enabled)\n\t\titem_flags |= option;\n\telse\n\t\titem_flags &= ~option;\n\tg.CurrentItemFlags = item_flags;\n\tg.ItemFlagsStack.push_back(item_flags);\n}\n\nvoid ImGui::PopItemFlag()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.\n\tg.ItemFlagsStack.pop_back();\n\tg.CurrentItemFlags = g.ItemFlagsStack.back();\n}\n\n// BeginDisabled()/EndDisabled()\n// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)\n// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.\n// - Feedback welcome at https://github.com/ocornut/imgui/issues/211\n// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.\n// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag()\nvoid ImGui::BeginDisabled(bool disabled)\n{\n\tImGuiContext& g = *GImGui;\n\tbool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;\n\tif (!was_disabled && disabled)\n\t{\n\t\tg.DisabledAlphaBackup = g.Style.Alpha;\n\t\tg.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);\n\t}\n\tif (was_disabled || disabled)\n\t\tg.CurrentItemFlags |= ImGuiItemFlags_Disabled;\n\tg.ItemFlagsStack.push_back(g.CurrentItemFlags);\n\tg.DisabledStackSize++;\n}\n\nvoid ImGui::EndDisabled()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.DisabledStackSize > 0);\n\tg.DisabledStackSize--;\n\tbool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;\n\t//PopItemFlag();\n\tg.ItemFlagsStack.pop_back();\n\tg.CurrentItemFlags = g.ItemFlagsStack.back();\n\tif (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)\n\t\tg.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();\n}\n\nvoid ImGui::PushTabStop(bool tab_stop)\n{\n\tPushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop);\n}\n\nvoid ImGui::PopTabStop()\n{\n\tPopItemFlag();\n}\n\nvoid ImGui::PushButtonRepeat(bool repeat)\n{\n\tPushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);\n}\n\nvoid ImGui::PopButtonRepeat()\n{\n\tPopItemFlag();\n}\n\nvoid ImGui::PushTextWrapPos(float wrap_pos_x)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);\n\twindow->DC.TextWrapPos = wrap_pos_x;\n}\n\nvoid ImGui::PopTextWrapPos()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.TextWrapPos = window->DC.TextWrapPosStack.back();\n\twindow->DC.TextWrapPosStack.pop_back();\n}\n\nstatic ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy)\n{\n\tImGuiWindow* last_window = NULL;\n\twhile (last_window != window)\n\t{\n\t\tlast_window = window;\n\t\twindow = window->RootWindow;\n\t\tif (popup_hierarchy)\n\t\t\twindow = window->RootWindowPopupTree;\n\t}\n\treturn window;\n}\n\nbool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy)\n{\n\tImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy);\n\tif (window_root == potential_parent)\n\t\treturn true;\n\twhile (window != NULL)\n\t{\n\t\tif (window == potential_parent)\n\t\t\treturn true;\n\t\tif (window == window_root) // end of chain\n\t\t\treturn false;\n\t\twindow = window->ParentWindow;\n\t}\n\treturn false;\n}\n\nbool ImGui::IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent)\n{\n\tif (window->RootWindow == potential_parent)\n\t\treturn true;\n\twhile (window != NULL)\n\t{\n\t\tif (window == potential_parent)\n\t\t\treturn true;\n\t\twindow = window->ParentWindowInBeginStack;\n\t}\n\treturn false;\n}\n\nbool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array\n\tconst int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below);\n\tif (display_layer_delta != 0)\n\t\treturn display_layer_delta > 0;\n\n\tfor (int i = g.Windows.Size - 1; i >= 0; i--)\n\t{\n\t\tImGuiWindow* candidate_window = g.Windows[i];\n\t\tif (candidate_window == potential_above)\n\t\t\treturn true;\n\t\tif (candidate_window == potential_below)\n\t\t\treturn false;\n\t}\n\treturn false;\n}\n\nbool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)\n{\n\tIM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0 && \"Invalid flags for IsWindowHovered()!\");\n\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* ref_window = g.HoveredWindow;\n\tImGuiWindow* cur_window = g.CurrentWindow;\n\tif (ref_window == NULL)\n\t\treturn false;\n\n\tif ((flags & ImGuiHoveredFlags_AnyWindow) == 0)\n\t{\n\t\tIM_ASSERT(cur_window); // Not inside a Begin()/End()\n\t\tconst bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0;\n\t\tif (flags & ImGuiHoveredFlags_RootWindow)\n\t\t\tcur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);\n\n\t\tbool result;\n\t\tif (flags & ImGuiHoveredFlags_ChildWindows)\n\t\t\tresult = IsWindowChildOf(ref_window, cur_window, popup_hierarchy);\n\t\telse\n\t\t\tresult = (ref_window == cur_window);\n\t\tif (!result)\n\t\t\treturn false;\n\t}\n\n\tif (!IsWindowContentHoverable(ref_window, flags))\n\t\treturn false;\n\tif (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))\n\t\tif (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId)\n\t\t\treturn false;\n\n\t// When changing hovered window we requires a bit of stationary delay before activating hover timer.\n\t// FIXME: We don't support delay other than stationary one for now, other delay would need a way\n\t// to fullfill the possibility that multiple IsWindowHovered() with varying flag could return true\n\t// for different windows of the hierarchy. Possibly need a Hash(Current+Flags) ==> (Timer) cache.\n\t// We can implement this for _Stationary because the data is linked to HoveredWindow rather than CurrentWindow.\n\tif (flags & ImGuiHoveredFlags_ForTooltip)\n\t\tflags |= g.Style.HoverFlagsForTooltipMouse;\n\tif ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverWindowUnlockedStationaryId != ref_window->ID)\n\t\treturn false;\n\n\treturn true;\n}\n\nbool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* ref_window = g.NavWindow;\n\tImGuiWindow* cur_window = g.CurrentWindow;\n\n\tif (ref_window == NULL)\n\t\treturn false;\n\tif (flags & ImGuiFocusedFlags_AnyWindow)\n\t\treturn true;\n\n\tIM_ASSERT(cur_window); // Not inside a Begin()/End()\n\tconst bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0;\n\tif (flags & ImGuiHoveredFlags_RootWindow)\n\t\tcur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);\n\n\tif (flags & ImGuiHoveredFlags_ChildWindows)\n\t\treturn IsWindowChildOf(ref_window, cur_window, popup_hierarchy);\n\telse\n\t\treturn (ref_window == cur_window);\n}\n\n// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)\n// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.\n// If you want a window to never be focused, you may use the e.g. NoInputs flag.\nbool ImGui::IsWindowNavFocusable(ImGuiWindow* window)\n{\n\treturn window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);\n}\n\nfloat ImGui::GetWindowWidth()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->Size.x;\n}\n\nfloat ImGui::GetWindowHeight()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->Size.y;\n}\n\nImVec2 ImGui::GetWindowPos()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\treturn window->Pos;\n}\n\nvoid ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)\n{\n\t// Test condition (NB: bit 0 is always true) and clear flags for next time\n\tif (cond && (window->SetWindowPosAllowFlags & cond) == 0)\n\t\treturn;\n\n\tIM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.\n\twindow->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);\n\twindow->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);\n\n\t// Set\n\tconst ImVec2 old_pos = window->Pos;\n\twindow->Pos = ImFloor(pos);\n\tImVec2 offset = window->Pos - old_pos;\n\tif (offset.x == 0.0f && offset.y == 0.0f)\n\t\treturn;\n\tMarkIniSettingsDirty(window);\n\twindow->DC.CursorPos += offset;         // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor\n\twindow->DC.CursorMaxPos += offset;      // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.\n\twindow->DC.IdealMaxPos += offset;\n\twindow->DC.CursorStartPos += offset;\n}\n\nvoid ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tSetWindowPos(window, pos, cond);\n}\n\nvoid ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)\n{\n\tif (ImGuiWindow* window = FindWindowByName(name))\n\t\tSetWindowPos(window, pos, cond);\n}\n\nImVec2 ImGui::GetWindowSize()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->Size;\n}\n\nvoid ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)\n{\n\t// Test condition (NB: bit 0 is always true) and clear flags for next time\n\tif (cond && (window->SetWindowSizeAllowFlags & cond) == 0)\n\t\treturn;\n\n\tIM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.\n\twindow->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);\n\n\t// Set\n\tImVec2 old_size = window->SizeFull;\n\twindow->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0;\n\twindow->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0;\n\tif (size.x <= 0.0f)\n\t\twindow->AutoFitOnlyGrows = false;\n\telse\n\t\twindow->SizeFull.x = IM_FLOOR(size.x);\n\tif (size.y <= 0.0f)\n\t\twindow->AutoFitOnlyGrows = false;\n\telse\n\t\twindow->SizeFull.y = IM_FLOOR(size.y);\n\tif (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y)\n\t\tMarkIniSettingsDirty(window);\n}\n\nvoid ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)\n{\n\tSetWindowSize(GImGui->CurrentWindow, size, cond);\n}\n\nvoid ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)\n{\n\tif (ImGuiWindow* window = FindWindowByName(name))\n\t\tSetWindowSize(window, size, cond);\n}\n\nvoid ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)\n{\n\t// Test condition (NB: bit 0 is always true) and clear flags for next time\n\tif (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)\n\t\treturn;\n\twindow->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);\n\n\t// Set\n\twindow->Collapsed = collapsed;\n}\n\nvoid ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)\n{\n\tIM_ASSERT(window->HitTestHoleSize.x == 0);     // We don't support multiple holes/hit test filters\n\twindow->HitTestHoleSize = ImVec2ih(size);\n\twindow->HitTestHoleOffset = ImVec2ih(pos - window->Pos);\n}\n\nvoid ImGui::SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window)\n{\n\twindow->Hidden = window->SkipItems = true;\n\twindow->HiddenFramesCanSkipItems = 1;\n}\n\nvoid ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)\n{\n\tSetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);\n}\n\nbool ImGui::IsWindowCollapsed()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->Collapsed;\n}\n\nbool ImGui::IsWindowAppearing()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->Appearing;\n}\n\nvoid ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)\n{\n\tif (ImGuiWindow* window = FindWindowByName(name))\n\t\tSetWindowCollapsed(window, collapsed, cond);\n}\n\nvoid ImGui::SetWindowFocus()\n{\n\tFocusWindow(GImGui->CurrentWindow);\n}\n\nvoid ImGui::SetWindowFocus(const char* name)\n{\n\tif (name)\n\t{\n\t\tif (ImGuiWindow* window = FindWindowByName(name))\n\t\t\tFocusWindow(window);\n\t}\n\telse\n\t{\n\t\tFocusWindow(NULL);\n\t}\n}\n\nvoid ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;\n\tg.NextWindowData.PosVal = pos;\n\tg.NextWindowData.PosPivotVal = pivot;\n\tg.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;\n}\n\nvoid ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;\n\tg.NextWindowData.SizeVal = size;\n\tg.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;\n}\n\nvoid ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;\n\tg.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);\n\tg.NextWindowData.SizeCallback = custom_callback;\n\tg.NextWindowData.SizeCallbackUserData = custom_callback_user_data;\n}\n\n// Content size = inner scrollable rectangle, padded with WindowPadding.\n// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.\nvoid ImGui::SetNextWindowContentSize(const ImVec2& size)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;\n\tg.NextWindowData.ContentSizeVal = ImFloor(size);\n}\n\nvoid ImGui::SetNextWindowScroll(const ImVec2& scroll)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll;\n\tg.NextWindowData.ScrollVal = scroll;\n}\n\nvoid ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;\n\tg.NextWindowData.CollapsedVal = collapsed;\n\tg.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;\n}\n\nvoid ImGui::SetNextWindowFocus()\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;\n}\n\nvoid ImGui::SetNextWindowBgAlpha(float alpha)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;\n\tg.NextWindowData.BgAlphaVal = alpha;\n}\n\nImDrawList* ImGui::GetWindowDrawList()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\treturn window->DrawList;\n}\n\nImFont* ImGui::GetFont()\n{\n\treturn GImGui->Font;\n}\n\nfloat ImGui::GetFontSize()\n{\n\treturn GImGui->FontSize;\n}\n\nImVec2 ImGui::GetFontTexUvWhitePixel()\n{\n\treturn GImGui->DrawListSharedData.TexUvWhitePixel;\n}\n\nvoid ImGui::SetWindowFontScale(float scale)\n{\n\tIM_ASSERT(scale > 0.0f);\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->FontWindowScale = scale;\n\tg.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();\n}\n\nvoid ImGui::PushFocusScope(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tg.FocusScopeStack.push_back(id);\n\tg.CurrentFocusScopeId = id;\n}\n\nvoid ImGui::PopFocusScope()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ?\n\tg.FocusScopeStack.pop_back();\n\tg.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back() : 0;\n}\n\n// Focus = move navigation cursor, set scrolling, set focus window.\nvoid ImGui::FocusItem()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIMGUI_DEBUG_LOG_FOCUS(\"FocusItem(0x%08x) in window \\\"%s\\\"\\n\", g.LastItemData.ID, window->Name);\n\tif (g.DragDropActive || g.MovingWindow != NULL) // FIXME: Opt-in flags for this?\n\t{\n\t\tIMGUI_DEBUG_LOG_FOCUS(\"FocusItem() ignored while DragDropActive!\\n\");\n\t\treturn;\n\t}\n\n\tImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSelect;\n\tImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;\n\tSetNavWindow(window);\n\tNavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags);\n\tNavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal);\n}\n\nvoid ImGui::ActivateItemByID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavNextActivateId = id;\n\tg.NavNextActivateFlags = ImGuiActivateFlags_None;\n}\n\n// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system!\n// But ActivateItem() should function without altering scroll/focus?\nvoid ImGui::SetKeyboardFocusHere(int offset)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(offset >= -1);    // -1 is allowed but not below\n\tIMGUI_DEBUG_LOG_FOCUS(\"SetKeyboardFocusHere(%d) in window \\\"%s\\\"\\n\", offset, window->Name);\n\n\t// It makes sense in the vast majority of cases to never interrupt a drag and drop.\n\t// When we refactor this function into ActivateItem() we may want to make this an option.\n\t// MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but\n\t// is also automatically dropped in the event g.ActiveId is stolen.\n\tif (g.DragDropActive || g.MovingWindow != NULL)\n\t{\n\t\tIMGUI_DEBUG_LOG_FOCUS(\"SetKeyboardFocusHere() ignored while DragDropActive!\\n\");\n\t\treturn;\n\t}\n\n\tSetNavWindow(window);\n\n\tImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi;\n\tImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;\n\tNavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.\n\tif (offset == -1)\n\t{\n\t\tNavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal);\n\t}\n\telse\n\t{\n\t\tg.NavTabbingDir = 1;\n\t\tg.NavTabbingCounter = offset + 1;\n\t}\n}\n\nvoid ImGui::SetItemDefaultFocus()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (!window->Appearing)\n\t\treturn;\n\tif (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResult.ID == 0) || g.NavLayer != window->DC.NavLayerCurrent)\n\t\treturn;\n\n\tg.NavInitRequest = false;\n\tNavApplyItemToResult(&g.NavInitResult);\n\tNavUpdateAnyRequestFlag();\n\n\t// Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll)\n\tif (!window->ClipRect.Contains(g.LastItemData.Rect))\n\t\tScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags_None);\n}\n\nvoid ImGui::SetStateStorage(ImGuiStorage* tree)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\twindow->DC.StateStorage = tree ? tree : &window->StateStorage;\n}\n\nImGuiStorage* ImGui::GetStateStorage()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->DC.StateStorage;\n}\n\nvoid ImGui::PushID(const char* str_id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiID id = window->GetID(str_id);\n\twindow->IDStack.push_back(id);\n}\n\nvoid ImGui::PushID(const char* str_id_begin, const char* str_id_end)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiID id = window->GetID(str_id_begin, str_id_end);\n\twindow->IDStack.push_back(id);\n}\n\nvoid ImGui::PushID(const void* ptr_id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiID id = window->GetID(ptr_id);\n\twindow->IDStack.push_back(id);\n}\n\nvoid ImGui::PushID(int int_id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiID id = window->GetID(int_id);\n\twindow->IDStack.push_back(id);\n}\n\n// Push a given id value ignoring the ID stack as a seed.\nvoid ImGui::PushOverrideID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (g.DebugHookIdInfo == id)\n\t\tDebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);\n\twindow->IDStack.push_back(id);\n}\n\n// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call\n// (note that when using this pattern, TestEngine's \"Stack Tool\" will tend to not display the intermediate stack level.\n//  for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)\nImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)\n{\n\tImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);\n\tImGuiContext& g = *GImGui;\n\tif (g.DebugHookIdInfo == id)\n\t\tDebugHookIdInfo(id, ImGuiDataType_String, str, str_end);\n\treturn id;\n}\n\nImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed)\n{\n\tImGuiID id = ImHashData(&n, sizeof(n), seed);\n\tImGuiContext& g = *GImGui;\n\tif (g.DebugHookIdInfo == id)\n\t\tDebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);\n\treturn id;\n}\n\nvoid ImGui::PopID()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\tIM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window?\n\twindow->IDStack.pop_back();\n}\n\nImGuiID ImGui::GetID(const char* str_id)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->GetID(str_id);\n}\n\nImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->GetID(str_id_begin, str_id_end);\n}\n\nImGuiID ImGui::GetID(const void* ptr_id)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->GetID(ptr_id);\n}\n\nbool ImGui::IsRectVisible(const ImVec2& size)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));\n}\n\nbool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ClipRect.Overlaps(ImRect(rect_min, rect_max));\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] INPUTS\n//-----------------------------------------------------------------------------\n// - GetKeyData() [Internal]\n// - GetKeyIndex() [Internal]\n// - GetKeyName()\n// - GetKeyChordName() [Internal]\n// - CalcTypematicRepeatAmount() [Internal]\n// - GetTypematicRepeatRate() [Internal]\n// - GetKeyPressedAmount() [Internal]\n// - GetKeyMagnitude2d() [Internal]\n//-----------------------------------------------------------------------------\n// - UpdateKeyRoutingTable() [Internal]\n// - GetRoutingIdFromOwnerId() [Internal]\n// - GetShortcutRoutingData() [Internal]\n// - CalcRoutingScore() [Internal]\n// - SetShortcutRouting() [Internal]\n// - TestShortcutRouting() [Internal]\n//-----------------------------------------------------------------------------\n// - IsKeyDown()\n// - IsKeyPressed()\n// - IsKeyReleased()\n//-----------------------------------------------------------------------------\n// - IsMouseDown()\n// - IsMouseClicked()\n// - IsMouseReleased()\n// - IsMouseDoubleClicked()\n// - GetMouseClickedCount()\n// - IsMouseHoveringRect() [Internal]\n// - IsMouseDragPastThreshold() [Internal]\n// - IsMouseDragging()\n// - GetMousePos()\n// - GetMousePosOnOpeningCurrentPopup()\n// - IsMousePosValid()\n// - IsAnyMouseDown()\n// - GetMouseDragDelta()\n// - ResetMouseDragDelta()\n// - GetMouseCursor()\n// - SetMouseCursor()\n//-----------------------------------------------------------------------------\n// - UpdateAliasKey()\n// - GetMergedModsFromKeys()\n// - UpdateKeyboardInputs()\n// - UpdateMouseInputs()\n//-----------------------------------------------------------------------------\n// - LockWheelingWindow [Internal]\n// - FindBestWheelingWindow [Internal]\n// - UpdateMouseWheel() [Internal]\n//-----------------------------------------------------------------------------\n// - SetNextFrameWantCaptureKeyboard()\n// - SetNextFrameWantCaptureMouse()\n//-----------------------------------------------------------------------------\n// - GetInputSourceName() [Internal]\n// - DebugPrintInputEvent() [Internal]\n// - UpdateInputEvents() [Internal]\n//-----------------------------------------------------------------------------\n// - GetKeyOwner() [Internal]\n// - TestKeyOwner() [Internal]\n// - SetKeyOwner() [Internal]\n// - SetItemKeyOwner() [Internal]\n// - Shortcut() [Internal]\n//-----------------------------------------------------------------------------\n\nImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key)\n{\n\tImGuiContext& g = *ctx;\n\n\t// Special storage location for mods\n\tif (key & ImGuiMod_Mask_)\n\t\tkey = ConvertSingleModFlagToKey(ctx, key);\n\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tIM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END);\n\tif (IsLegacyKey(key) && g.IO.KeyMap[key] != -1)\n\t\tkey = (ImGuiKey)g.IO.KeyMap[key];  // Remap native->imgui or imgui->native\n#else\n\tIM_ASSERT(IsNamedKey(key) && \"Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code.\");\n#endif\n\treturn &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET];\n}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\nImGuiKey ImGui::GetKeyIndex(ImGuiKey key)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(IsNamedKey(key));\n\tconst ImGuiKeyData* key_data = GetKeyData(key);\n\treturn (ImGuiKey)(key_data - g.IO.KeysData);\n}\n#endif\n\n// Those names a provided for debugging purpose and are not meant to be saved persistently not compared.\nstatic const char* const GKeyNames[] =\n{\n\t\"Tab\", \"LeftArrow\", \"RightArrow\", \"UpArrow\", \"DownArrow\", \"PageUp\", \"PageDown\",\n\t\"Home\", \"End\", \"Insert\", \"Delete\", \"Backspace\", \"Space\", \"Enter\", \"Escape\",\n\t\"LeftCtrl\", \"LeftShift\", \"LeftAlt\", \"LeftSuper\", \"RightCtrl\", \"RightShift\", \"RightAlt\", \"RightSuper\", \"Menu\",\n\t\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\",\n\t\"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\",\n\t\"F1\", \"F2\", \"F3\", \"F4\", \"F5\", \"F6\", \"F7\", \"F8\", \"F9\", \"F10\", \"F11\", \"F12\",\n\t\"Apostrophe\", \"Comma\", \"Minus\", \"Period\", \"Slash\", \"Semicolon\", \"Equal\", \"LeftBracket\",\n\t\"Backslash\", \"RightBracket\", \"GraveAccent\", \"CapsLock\", \"ScrollLock\", \"NumLock\", \"PrintScreen\",\n\t\"Pause\", \"Keypad0\", \"Keypad1\", \"Keypad2\", \"Keypad3\", \"Keypad4\", \"Keypad5\", \"Keypad6\",\n\t\"Keypad7\", \"Keypad8\", \"Keypad9\", \"KeypadDecimal\", \"KeypadDivide\", \"KeypadMultiply\",\n\t\"KeypadSubtract\", \"KeypadAdd\", \"KeypadEnter\", \"KeypadEqual\",\n\t\"GamepadStart\", \"GamepadBack\",\n\t\"GamepadFaceLeft\", \"GamepadFaceRight\", \"GamepadFaceUp\", \"GamepadFaceDown\",\n\t\"GamepadDpadLeft\", \"GamepadDpadRight\", \"GamepadDpadUp\", \"GamepadDpadDown\",\n\t\"GamepadL1\", \"GamepadR1\", \"GamepadL2\", \"GamepadR2\", \"GamepadL3\", \"GamepadR3\",\n\t\"GamepadLStickLeft\", \"GamepadLStickRight\", \"GamepadLStickUp\", \"GamepadLStickDown\",\n\t\"GamepadRStickLeft\", \"GamepadRStickRight\", \"GamepadRStickUp\", \"GamepadRStickDown\",\n\t\"MouseLeft\", \"MouseRight\", \"MouseMiddle\", \"MouseX1\", \"MouseX2\", \"MouseWheelX\", \"MouseWheelY\",\n\t\"ModCtrl\", \"ModShift\", \"ModAlt\", \"ModSuper\", // ReservedForModXXX are showing the ModXXX names.\n};\nIM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames));\n\nconst char* ImGui::GetKeyName(ImGuiKey key)\n{\n\tImGuiContext& g = *GImGui;\n#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tIM_ASSERT((IsNamedKeyOrModKey(key) || key == ImGuiKey_None) && \"Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.\");\n#else\n\tif (IsLegacyKey(key))\n\t{\n\t\tif (g.IO.KeyMap[key] == -1)\n\t\t\treturn \"N/A\";\n\t\tIM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key]));\n\t\tkey = (ImGuiKey)g.IO.KeyMap[key];\n\t}\n#endif\n\tif (key == ImGuiKey_None)\n\t\treturn \"None\";\n\tif (key & ImGuiMod_Mask_)\n\t\tkey = ConvertSingleModFlagToKey(&g, key);\n\tif (!IsNamedKey(key))\n\t\treturn \"Unknown\";\n\n\treturn GKeyNames[key - ImGuiKey_NamedKey_BEGIN];\n}\n\n// ImGuiMod_Shortcut is translated to either Ctrl or Super.\nvoid ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)\n{\n\tImGuiContext& g = *GImGui;\n\tif (key_chord & ImGuiMod_Shortcut)\n\t\tkey_chord = ConvertShortcutMod(key_chord);\n\tImFormatString(out_buf, (size_t)out_buf_size, \"%s%s%s%s%s\",\n\t\t(key_chord & ImGuiMod_Ctrl) ? \"Ctrl+\" : \"\",\n\t\t(key_chord & ImGuiMod_Shift) ? \"Shift+\" : \"\",\n\t\t(key_chord & ImGuiMod_Alt) ? \"Alt+\" : \"\",\n\t\t(key_chord & ImGuiMod_Super) ? (g.IO.ConfigMacOSXBehaviors ? \"Cmd+\" : \"Super+\") : \"\",\n\t\tGetKeyName((ImGuiKey)(key_chord & ~ImGuiMod_Mask_)));\n}\n\n// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)\n// t1 = current time (e.g.: g.Time)\n// An event is triggered at:\n//  t = 0.0f     t = repeat_delay,    t = repeat_delay + repeat_rate*N\nint ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)\n{\n\tif (t1 == 0.0f)\n\t\treturn 1;\n\tif (t0 >= t1)\n\t\treturn 0;\n\tif (repeat_rate <= 0.0f)\n\t\treturn (t0 < repeat_delay) && (t1 >= repeat_delay);\n\tconst int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);\n\tconst int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);\n\tconst int count = count_t1 - count_t0;\n\treturn count;\n}\n\nvoid ImGui::GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate)\n{\n\tImGuiContext& g = *GImGui;\n\tswitch (flags & ImGuiInputFlags_RepeatRateMask_)\n\t{\n\tcase ImGuiInputFlags_RepeatRateNavMove:             *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.80f; return;\n\tcase ImGuiInputFlags_RepeatRateNavTweak:            *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.30f; return;\n\tcase ImGuiInputFlags_RepeatRateDefault: default:    *repeat_delay = g.IO.KeyRepeatDelay * 1.00f; *repeat_rate = g.IO.KeyRepeatRate * 1.00f; return;\n\t}\n}\n\n// Return value representing the number of presses in the last time period, for the given repeat rate\n// (most often returns 0 or 1. The result is generally only >1 when RepeatRate is smaller than DeltaTime, aka large DeltaTime or fast RepeatRate)\nint ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiKeyData* key_data = GetKeyData(key);\n\tif (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)\n\t\treturn 0;\n\tconst float t = key_data->DownDuration;\n\treturn CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);\n}\n\n// Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values).\nImVec2 ImGui::GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down)\n{\n\treturn ImVec2(\n\t\tGetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue,\n\t\tGetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue);\n}\n\n// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data.\n//   Entries   D,A,B,B,A,C,B     --> A,A,B,B,B,C,D\n//   Index     A:1 B:2 C:5 D:0   --> A:0 B:2 C:5 D:6\n// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation.\nstatic void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)\n{\n\tImGuiContext& g = *GImGui;\n\trt->EntriesNext.resize(0);\n\tfor (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))\n\t{\n\t\tconst int new_routing_start_idx = rt->EntriesNext.Size;\n\t\tImGuiKeyRoutingData* routing_entry;\n\t\tfor (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex)\n\t\t{\n\t\t\trouting_entry = &rt->Entries[old_routing_idx];\n\t\t\trouting_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry\n\t\t\trouting_entry->RoutingNext = ImGuiKeyOwner_None;\n\t\t\trouting_entry->RoutingNextScore = 255;\n\t\t\tif (routing_entry->RoutingCurr == ImGuiKeyOwner_None)\n\t\t\t\tcontinue;\n\t\t\trt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer\n\n\t\t\t// Apply routing to owner if there's no owner already (RoutingCurr == None at this point)\n\t\t\tif (routing_entry->Mods == g.IO.KeyMods)\n\t\t\t{\n\t\t\t\tImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);\n\t\t\t\tif (owner_data->OwnerCurr == ImGuiKeyOwner_None)\n\t\t\t\t\towner_data->OwnerCurr = routing_entry->RoutingCurr;\n\t\t\t}\n\t\t}\n\n\t\t// Rewrite linked-list\n\t\trt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1);\n\t\tfor (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++)\n\t\t\trt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1);\n\t}\n\trt->Entries.swap(rt->EntriesNext); // Swap new and old indexes\n}\n\n// owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope().\nstatic inline ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id)\n{\n\tImGuiContext& g = *GImGui;\n\treturn (owner_id != ImGuiKeyOwner_None && owner_id != ImGuiKeyOwner_Any) ? owner_id : g.CurrentFocusScopeId;\n}\n\nImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)\n{\n\t// Majority of shortcuts will be Key + any number of Mods\n\t// We accept _Single_ mod with ImGuiKey_None.\n\t//  - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl);                    // Legal\n\t//  - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl | ImGuiMod_Shift);   // Legal\n\t//  - Shortcut(ImGuiMod_Ctrl);                                 // Legal\n\t//  - Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift);                // Not legal\n\tImGuiContext& g = *GImGui;\n\tImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;\n\tImGuiKeyRoutingData* routing_data;\n\tif (key_chord & ImGuiMod_Shortcut)\n\t\tkey_chord = ConvertShortcutMod(key_chord);\n\tImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);\n\tImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);\n\tif (key == ImGuiKey_None)\n\t\tkey = ConvertSingleModFlagToKey(&g, mods);\n\tIM_ASSERT(IsNamedKey(key));\n\n\t// Get (in the majority of case, the linked list will have one element so this should be 2 reads.\n\t// Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame).\n\tfor (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; idx = routing_data->NextEntryIndex)\n\t{\n\t\trouting_data = &rt->Entries[idx];\n\t\tif (routing_data->Mods == mods)\n\t\t\treturn routing_data;\n\t}\n\n\t// Add to linked-list\n\tImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size;\n\trt->Entries.push_back(ImGuiKeyRoutingData());\n\trouting_data = &rt->Entries[routing_data_idx];\n\trouting_data->Mods = (ImU16)mods;\n\trouting_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list\n\trt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx;\n\treturn routing_data;\n}\n\n// Current score encoding (lower is highest priority):\n//  -   0: ImGuiInputFlags_RouteGlobalHigh\n//  -   1: ImGuiInputFlags_RouteFocused (if item active)\n//  -   2: ImGuiInputFlags_RouteGlobal\n//  -  3+: ImGuiInputFlags_RouteFocused (if window in focus-stack)\n//  - 254: ImGuiInputFlags_RouteGlobalLow\n//  - 255: never route\n// 'flags' should include an explicit routing policy\nstatic int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tif (flags & ImGuiInputFlags_RouteFocused)\n\t{\n\t\tImGuiContext& g = *GImGui;\n\t\tImGuiWindow* focused = g.NavWindow;\n\n\t\t// ActiveID gets top priority\n\t\t// (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it)\n\t\tif (owner_id != 0 && g.ActiveId == owner_id)\n\t\t\treturn 1;\n\n\t\t// Score based on distance to focused window (lower is better)\n\t\t// Assuming both windows are submitting a routing request,\n\t\t// - When Window....... is focused -> Window scores 3 (best), Window/ChildB scores 255 (no match)\n\t\t// - When Window/ChildB is focused -> Window scores 4,        Window/ChildB scores 3 (best)\n\t\t// Assuming only WindowA is submitting a routing request,\n\t\t// - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score.\n\t\tif (focused != NULL && focused->RootWindow == location->RootWindow)\n\t\t\tfor (int next_score = 3; focused != NULL; next_score++)\n\t\t\t{\n\t\t\t\tif (focused == location)\n\t\t\t\t{\n\t\t\t\t\tIM_ASSERT(next_score < 255);\n\t\t\t\t\treturn next_score;\n\t\t\t\t}\n\t\t\t\tfocused = (focused->RootWindow != focused) ? focused->ParentWindow : NULL; // FIXME: This could be later abstracted as a focus path\n\t\t\t}\n\t\treturn 255;\n\t}\n\n\t// ImGuiInputFlags_RouteGlobalHigh is default, so calls without flags are not conditional\n\tif (flags & ImGuiInputFlags_RouteGlobal)\n\t\treturn 2;\n\tif (flags & ImGuiInputFlags_RouteGlobalLow)\n\t\treturn 254;\n\treturn 0;\n}\n\n// Request a desired route for an input chord (key + mods).\n// Return true if the route is available this frame.\n// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state.\n//   (Conceptually this does a \"Submit for next frame\" + \"Test for current frame\".\n//   As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.)\n// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default)\n// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut.\nbool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif ((flags & ImGuiInputFlags_RouteMask_) == 0)\n\t\tflags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()\n\telse\n\t\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used\n\n\tif (flags & ImGuiInputFlags_RouteUnlessBgFocused)\n\t\tif (g.NavWindow == NULL)\n\t\t\treturn false;\n\tif (flags & ImGuiInputFlags_RouteAlways)\n\t\treturn true;\n\n\tconst int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags);\n\tif (score == 255)\n\t\treturn false;\n\n\t// Submit routing for NEXT frame (assuming score is sufficient)\n\t// FIXME: Could expose a way to use a \"serve last\" policy for same score resolution (using <= instead of <).\n\tImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);\n\tconst ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);\n\t//const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore);\n\tif (score < routing_data->RoutingNextScore)\n\t{\n\t\trouting_data->RoutingNext = routing_id;\n\t\trouting_data->RoutingNextScore = (ImU8)score;\n\t}\n\n\t// Return routing state for CURRENT frame\n\treturn routing_data->RoutingCurr == routing_id;\n}\n\n// Currently unused by core (but used by tests)\n// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading.\nbool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id)\n{\n\tconst ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);\n\tImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry.\n\treturn routing_data->RoutingCurr == routing_id;\n}\n\n// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes.\n// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87)\nbool ImGui::IsKeyDown(ImGuiKey key)\n{\n\treturn IsKeyDown(key, ImGuiKeyOwner_Any);\n}\n\nbool ImGui::IsKeyDown(ImGuiKey key, ImGuiID owner_id)\n{\n\tconst ImGuiKeyData* key_data = GetKeyData(key);\n\tif (!key_data->Down)\n\t\treturn false;\n\tif (!TestKeyOwner(key, owner_id))\n\t\treturn false;\n\treturn true;\n}\n\nbool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)\n{\n\treturn IsKeyPressed(key, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None);\n}\n\n// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.\nbool ImGui::IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tconst ImGuiKeyData* key_data = GetKeyData(key);\n\tif (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)\n\t\treturn false;\n\tconst float t = key_data->DownDuration;\n\tif (t < 0.0f)\n\t\treturn false;\n\tIM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function!\n\n\tbool pressed = (t == 0.0f);\n\tif (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0))\n\t{\n\t\tfloat repeat_delay, repeat_rate;\n\t\tGetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate);\n\t\tpressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0;\n\t}\n\tif (!pressed)\n\t\treturn false;\n\tif (!TestKeyOwner(key, owner_id))\n\t\treturn false;\n\treturn true;\n}\n\nbool ImGui::IsKeyReleased(ImGuiKey key)\n{\n\treturn IsKeyReleased(key, ImGuiKeyOwner_Any);\n}\n\nbool ImGui::IsKeyReleased(ImGuiKey key, ImGuiID owner_id)\n{\n\tconst ImGuiKeyData* key_data = GetKeyData(key);\n\tif (key_data->DownDurationPrev < 0.0f || key_data->Down)\n\t\treturn false;\n\tif (!TestKeyOwner(key, owner_id))\n\t\treturn false;\n\treturn true;\n}\n\nbool ImGui::IsMouseDown(ImGuiMouseButton button)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array.\n}\n\nbool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array.\n}\n\nbool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)\n{\n\treturn IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None);\n}\n\nbool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\tif (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)\n\t\treturn false;\n\tconst float t = g.IO.MouseDownDuration[button];\n\tif (t < 0.0f)\n\t\treturn false;\n\tIM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function!\n\n\tconst bool repeat = (flags & ImGuiInputFlags_Repeat) != 0;\n\tconst bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0);\n\tif (!pressed)\n\t\treturn false;\n\n\tif (!TestKeyOwner(MouseButtonToKey(button), owner_id))\n\t\treturn false;\n\n\treturn true;\n}\n\nbool ImGui::IsMouseReleased(ImGuiMouseButton button)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any)\n}\n\nbool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id)\n}\n\nbool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any);\n}\n\nint ImGui::GetMouseClickedCount(ImGuiMouseButton button)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\treturn g.IO.MouseClickedCount[button];\n}\n\n// Test if mouse cursor is hovering given rectangle\n// NB- Rectangle is clipped by our current clip setting\n// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)\nbool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Clip\n\tImRect rect_clipped(r_min, r_max);\n\tif (clip)\n\t\trect_clipped.ClipWith(g.CurrentWindow->ClipRect);\n\n\t// Expand for touch input\n\tconst ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);\n\tif (!rect_for_touch.Contains(g.IO.MousePos))\n\t\treturn false;\n\treturn true;\n}\n\n// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.\n// [Internal] This doesn't test if the button is pressed\nbool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\tif (lock_threshold < 0.0f)\n\t\tlock_threshold = g.IO.MouseDragThreshold;\n\treturn g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;\n}\n\nbool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\tif (!g.IO.MouseDown[button])\n\t\treturn false;\n\treturn IsMouseDragPastThreshold(button, lock_threshold);\n}\n\nImVec2 ImGui::GetMousePos()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.IO.MousePos;\n}\n\n// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!\nImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.BeginPopupStack.Size > 0)\n\t\treturn g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;\n\treturn g.IO.MousePos;\n}\n\n// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.\nbool ImGui::IsMousePosValid(const ImVec2* mouse_pos)\n{\n\t// The assert is only to silence a false-positive in XCode Static Analysis.\n\t// Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).\n\tIM_ASSERT(GImGui != NULL);\n\tconst float MOUSE_INVALID = -256000.0f;\n\tImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;\n\treturn p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;\n}\n\n// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid.\nbool ImGui::IsAnyMouseDown()\n{\n\tImGuiContext& g = *GImGui;\n\tfor (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)\n\t\tif (g.IO.MouseDown[n])\n\t\t\treturn true;\n\treturn false;\n}\n\n// Return the delta from the initial clicking position while the mouse button is clicked or was just released.\n// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.\n// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.\nImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\tif (lock_threshold < 0.0f)\n\t\tlock_threshold = g.IO.MouseDragThreshold;\n\tif (g.IO.MouseDown[button] || g.IO.MouseReleased[button])\n\t\tif (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)\n\t\t\tif (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))\n\t\t\t\treturn g.IO.MousePos - g.IO.MouseClickedPos[button];\n\treturn ImVec2(0.0f, 0.0f);\n}\n\nvoid ImGui::ResetMouseDragDelta(ImGuiMouseButton button)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));\n\t// NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr\n\tg.IO.MouseClickedPos[button] = g.IO.MousePos;\n}\n\n// Get desired mouse cursor shape.\n// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(),\n// updated during the frame, and locked in EndFrame()/Render().\n// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you\nImGuiMouseCursor ImGui::GetMouseCursor()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.MouseCursor;\n}\n\nvoid ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)\n{\n\tImGuiContext& g = *GImGui;\n\tg.MouseCursor = cursor_type;\n}\n\nstatic void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)\n{\n\tIM_ASSERT(ImGui::IsAliasKey(key));\n\tImGuiKeyData* key_data = ImGui::GetKeyData(key);\n\tkey_data->Down = v;\n\tkey_data->AnalogValue = analog_value;\n}\n\n// [Internal] Do not use directly\nstatic ImGuiKeyChord GetMergedModsFromKeys()\n{\n\tImGuiKeyChord mods = 0;\n\tif (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; }\n\tif (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; }\n\tif (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; }\n\tif (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; }\n\treturn mods;\n}\n\nstatic void ImGui::UpdateKeyboardInputs()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\n\t// Import legacy keys or verify they are not used\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tif (io.BackendUsingLegacyKeyArrays == 0)\n\t{\n\t\t// Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally.\n\t\tfor (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++)\n\t\t\tIM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && \"Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!\");\n\t}\n\telse\n\t{\n\t\tif (g.FrameCount == 0)\n\t\t\tfor (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++)\n\t\t\t\tIM_ASSERT(g.IO.KeyMap[n] == -1 && \"Backend is not allowed to write to io.KeyMap[0..511]!\");\n\n\t\t// Build reverse KeyMap (Named -> Legacy)\n\t\tfor (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)\n\t\t\tif (io.KeyMap[n] != -1)\n\t\t\t{\n\t\t\t\tIM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n]));\n\t\t\t\tio.KeyMap[io.KeyMap[n]] = n;\n\t\t\t}\n\n\t\t// Import legacy keys into new ones\n\t\tfor (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++)\n\t\t\tif (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1)\n\t\t\t{\n\t\t\t\tconst ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n);\n\t\t\t\tIM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key));\n\t\t\t\tio.KeysData[key].Down = io.KeysDown[n];\n\t\t\t\tif (key != n)\n\t\t\t\t\tio.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends\n\t\t\t\tio.BackendUsingLegacyKeyArrays = 1;\n\t\t\t}\n\t\tif (io.BackendUsingLegacyKeyArrays == 1)\n\t\t{\n\t\t\tGetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl;\n\t\t\tGetKeyData(ImGuiMod_Shift)->Down = io.KeyShift;\n\t\t\tGetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt;\n\t\t\tGetKeyData(ImGuiMod_Super)->Down = io.KeySuper;\n\t\t}\n\t}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tconst bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\tif (io.BackendUsingLegacyNavInputArray && nav_gamepad_active)\n\t{\n#define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1)           do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0)\n#define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2)    do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0)\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp);\n\t\tMAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown);\n#undef NAV_MAP_KEY\n\t}\n#endif\n#endif\n\n\t// Update aliases\n\tfor (int n = 0; n < ImGuiMouseButton_COUNT; n++)\n\t\tUpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f);\n\tUpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH);\n\tUpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel);\n\n\t// Synchronize io.KeyMods and io.KeyXXX values.\n\t// - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) ->                                      -> (here) deriving io.KeyMods + io.KeyXXX from key array.\n\t// - Legacy backends:      set io.KeyXXX bools               -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array.\n\t// So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing.\n\tio.KeyMods = GetMergedModsFromKeys();\n\tio.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0;\n\tio.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0;\n\tio.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0;\n\tio.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0;\n\n\t// Clear gamepad data if disabled\n\tif ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)\n\t\tfor (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)\n\t\t{\n\t\t\tio.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false;\n\t\t\tio.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f;\n\t\t}\n\n\t// Update keys\n\tfor (int i = 0; i < ImGuiKey_KeysData_SIZE; i++)\n\t{\n\t\tImGuiKeyData* key_data = &io.KeysData[i];\n\t\tkey_data->DownDurationPrev = key_data->DownDuration;\n\t\tkey_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f;\n\t}\n\n\t// Update keys/input owner (named keys only): one entry per key\n\tfor (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))\n\t{\n\t\tImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET];\n\t\tImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN];\n\t\towner_data->OwnerCurr = owner_data->OwnerNext;\n\t\tif (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp.\n\t\t\towner_data->OwnerNext = ImGuiKeyOwner_None;\n\t\towner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down;  // Clear LockUntilRelease when key is not Down anymore\n\t}\n\n\tUpdateKeyRoutingTable(&g.KeysRoutingTable);\n}\n\nstatic void ImGui::UpdateMouseInputs()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\n\t// Mouse Wheel swapping flag\n\t// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead\n\t// - We avoid doing it on OSX as it the OS input layer handles this already.\n\t// - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature.\n\t// - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source.\n\tio.MouseWheelRequestAxisSwap = io.KeyShift && !io.ConfigMacOSXBehaviors;\n\n\t// Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)\n\tif (IsMousePosValid(&io.MousePos))\n\t\tio.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);\n\n\t// If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta\n\tif (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev))\n\t\tio.MouseDelta = io.MousePos - io.MousePosPrev;\n\telse\n\t\tio.MouseDelta = ImVec2(0.0f, 0.0f);\n\n\t// Update stationary timer.\n\t// FIXME: May need to rework again to have some tolerance for occasional small movement, while being functional on high-framerates.\n\tconst float mouse_stationary_threshold = (io.MouseSource == ImGuiMouseSource_Mouse) ? 2.0f : 3.0f; // Slightly higher threshold for ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen, may need rework.\n\tconst bool mouse_stationary = (ImLengthSqr(io.MouseDelta) <= mouse_stationary_threshold * mouse_stationary_threshold);\n\tg.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f;\n\t//IMGUI_DEBUG_LOG(\"%.4f\\n\", g.MouseStationaryTimer);\n\n\t// If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true.\n\tif (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)\n\t\tg.NavDisableMouseHover = false;\n\n\tio.MousePosPrev = io.MousePos;\n\tfor (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)\n\t{\n\t\tio.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f;\n\t\tio.MouseClickedCount[i] = 0; // Will be filled below\n\t\tio.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f;\n\t\tio.MouseDownDurationPrev[i] = io.MouseDownDuration[i];\n\t\tio.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f;\n\t\tif (io.MouseClicked[i])\n\t\t{\n\t\t\tbool is_repeated_click = false;\n\t\t\tif ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime)\n\t\t\t{\n\t\t\t\tImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);\n\t\t\t\tif (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist)\n\t\t\t\t\tis_repeated_click = true;\n\t\t\t}\n\t\t\tif (is_repeated_click)\n\t\t\t\tio.MouseClickedLastCount[i]++;\n\t\t\telse\n\t\t\t\tio.MouseClickedLastCount[i] = 1;\n\t\t\tio.MouseClickedTime[i] = g.Time;\n\t\t\tio.MouseClickedPos[i] = io.MousePos;\n\t\t\tio.MouseClickedCount[i] = io.MouseClickedLastCount[i];\n\t\t\tio.MouseDragMaxDistanceSqr[i] = 0.0f;\n\t\t}\n\t\telse if (io.MouseDown[i])\n\t\t{\n\t\t\t// Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold\n\t\t\tfloat delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f;\n\t\t\tio.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos);\n\t\t}\n\n\t\t// We provide io.MouseDoubleClicked[] as a legacy service\n\t\tio.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2);\n\n\t\t// Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation\n\t\tif (io.MouseClicked[i])\n\t\t\tg.NavDisableMouseHover = false;\n\t}\n}\n\nstatic void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)\n{\n\tImGuiContext& g = *GImGui;\n\tif (window)\n\t\tg.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER);\n\telse\n\t\tg.WheelingWindowReleaseTimer = 0.0f;\n\tif (g.WheelingWindow == window)\n\t\treturn;\n\tIMGUI_DEBUG_LOG_IO(\"[io] LockWheelingWindow() \\\"%s\\\"\\n\", window ? window->Name : \"NULL\");\n\tg.WheelingWindow = window;\n\tg.WheelingWindowRefMousePos = g.IO.MousePos;\n\tif (window == NULL)\n\t{\n\t\tg.WheelingWindowStartFrame = -1;\n\t\tg.WheelingAxisAvg = ImVec2(0.0f, 0.0f);\n\t}\n}\n\nstatic ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)\n{\n\t// For each axis, find window in the hierarchy that may want to use scrolling\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* windows[2] = { NULL, NULL };\n\tfor (int axis = 0; axis < 2; axis++)\n\t\tif (wheel[axis] != 0.0f)\n\t\t\tfor (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)\n\t\t\t{\n\t\t\t\t// Bubble up into parent window if:\n\t\t\t\t// - a child window doesn't allow any scrolling.\n\t\t\t\t// - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.\n\t\t\t\t//// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP)\n\t\t\t\tconst bool has_scrolling = (window->ScrollMax[axis] != 0.0f);\n\t\t\t\tconst bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);\n\t\t\t\t//const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);\n\t\t\t\tif (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)\n\t\t\t\t\tbreak; // select this window\n\t\t\t}\n\tif (windows[0] == NULL && windows[1] == NULL)\n\t\treturn NULL;\n\n\t// If there's only one window or only one axis then there's no ambiguity\n\tif (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)\n\t\treturn windows[1] ? windows[1] : windows[0];\n\n\t// If candidate are different windows we need to decide which one to prioritize\n\t// - First frame: only find a winner if one axis is zero.\n\t// - Subsequent frames: only find a winner when one is more than the other.\n\tif (g.WheelingWindowStartFrame == -1)\n\t\tg.WheelingWindowStartFrame = g.FrameCount;\n\tif ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))\n\t{\n\t\tg.WheelingWindowWheelRemainder = wheel;\n\t\treturn NULL;\n\t}\n\treturn (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];\n}\n\n// Called by NewFrame()\nvoid ImGui::UpdateMouseWheel()\n{\n\t// Reset the locked window if we move the mouse or after the timer elapses.\n\t// FIXME: Ideally we could refactor to have one timer for \"changing window w/ same axis\" and a shorter timer for \"changing window or axis w/ other axis\" (#3795)\n\tImGuiContext& g = *GImGui;\n\tif (g.WheelingWindow != NULL)\n\t{\n\t\tg.WheelingWindowReleaseTimer -= g.IO.DeltaTime;\n\t\tif (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)\n\t\t\tg.WheelingWindowReleaseTimer = 0.0f;\n\t\tif (g.WheelingWindowReleaseTimer <= 0.0f)\n\t\t\tLockWheelingWindow(NULL, 0.0f);\n\t}\n\n\tImVec2 wheel;\n\twheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f;\n\twheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f;\n\n\t//IMGUI_DEBUG_LOG(\"MouseWheel X:%.3f Y:%.3f\\n\", wheel_x, wheel_y);\n\tImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;\n\tif (!mouse_window || mouse_window->Collapsed)\n\t\treturn;\n\n\t// Zoom / Scale window\n\t// FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.\n\tif (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)\n\t{\n\t\tLockWheelingWindow(mouse_window, wheel.y);\n\t\tImGuiWindow* window = mouse_window;\n\t\tconst float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);\n\t\tconst float scale = new_font_scale / window->FontWindowScale;\n\t\twindow->FontWindowScale = new_font_scale;\n\t\tif (window == window->RootWindow)\n\t\t{\n\t\t\tconst ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;\n\t\t\tSetWindowPos(window, window->Pos + offset, 0);\n\t\t\twindow->Size = ImFloor(window->Size * scale);\n\t\t\twindow->SizeFull = ImFloor(window->SizeFull * scale);\n\t\t}\n\t\treturn;\n\t}\n\tif (g.IO.KeyCtrl)\n\t\treturn;\n\n\t// Mouse wheel scrolling\n\t// Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs()\n\tif (g.IO.MouseWheelRequestAxisSwap)\n\t\twheel = ImVec2(wheel.y, 0.0f);\n\n\t// Maintain a rough average of moving magnitude on both axises\n\t// FIXME: should by based on wall clock time rather than frame-counter\n\tg.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30);\n\tg.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30);\n\n\t// In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.\n\twheel += g.WheelingWindowWheelRemainder;\n\tg.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);\n\tif (wheel.x == 0.0f && wheel.y == 0.0f)\n\t\treturn;\n\n\t// Mouse wheel scrolling: find target and apply\n\t// - don't renew lock if axis doesn't apply on the window.\n\t// - select a main axis when both axises are being moved.\n\tif (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))\n\t\tif (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))\n\t\t{\n\t\t\tbool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };\n\t\t\tif (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])\n\t\t\t\tdo_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;\n\t\t\tif (do_scroll[ImGuiAxis_X])\n\t\t\t{\n\t\t\t\tLockWheelingWindow(window, wheel.x);\n\t\t\t\tfloat max_step = window->InnerRect.GetWidth() * 0.67f;\n\t\t\t\tfloat scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));\n\t\t\t\tSetScrollX(window, window->Scroll.x - wheel.x * scroll_step);\n\t\t\t}\n\t\t\tif (do_scroll[ImGuiAxis_Y])\n\t\t\t{\n\t\t\t\tLockWheelingWindow(window, wheel.y);\n\t\t\t\tfloat max_step = window->InnerRect.GetHeight() * 0.67f;\n\t\t\t\tfloat scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));\n\t\t\t\tSetScrollY(window, window->Scroll.y - wheel.y * scroll_step);\n\t\t\t}\n\t\t}\n}\n\nvoid ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)\n{\n\tImGuiContext& g = *GImGui;\n\tg.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0;\n}\n\nvoid ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)\n{\n\tImGuiContext& g = *GImGui;\n\tg.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0;\n}\n\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\nstatic const char* GetInputSourceName(ImGuiInputSource source)\n{\n\tconst char* input_source_names[] = { \"None\", \"Mouse\", \"Keyboard\", \"Gamepad\", \"Clipboard\" };\n\tIM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);\n\treturn input_source_names[source];\n}\nstatic const char* GetMouseSourceName(ImGuiMouseSource source)\n{\n\tconst char* mouse_source_names[] = { \"Mouse\", \"TouchScreen\", \"Pen\" };\n\tIM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT);\n\treturn mouse_source_names[source];\n}\nstatic void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)\n{\n\tImGuiContext& g = *GImGui;\n\tif (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO(\"[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\\n\", prefix); else IMGUI_DEBUG_LOG_IO(\"[io] %s: MousePos (%.1f, %.1f) (%s)\\n\", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; }\n\tif (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO(\"[io] %s: MouseButton %d %s (%s)\\n\", prefix, e->MouseButton.Button, e->MouseButton.Down ? \"Down\" : \"Up\", GetMouseSourceName(e->MouseButton.MouseSource)); return; }\n\tif (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO(\"[io] %s: MouseWheel (%.3f, %.3f) (%s)\\n\", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }\n\tif (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO(\"[io] %s: Key \\\"%s\\\" %s\\n\", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? \"Down\" : \"Up\"); return; }\n\tif (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO(\"[io] %s: Text: %c (U+%08X)\\n\", prefix, e->Text.Char, e->Text.Char); return; }\n\tif (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO(\"[io] %s: AppFocused %d\\n\", prefix, e->AppFocused.Focused); return; }\n}\n#endif\n\n// Process input queue\n// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'.\n// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)\n// - trickle_fast_inputs = true  : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)\nvoid ImGui::UpdateInputEvents(bool trickle_fast_inputs)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\n\t// Only trickle chars<>key when working with InputText()\n\t// FIXME: InputText() could parse event trail?\n\t// FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters)\n\tconst bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1);\n\n\tbool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false;\n\tint  mouse_button_changed = 0x00;\n\tImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;\n\n\tint event_n = 0;\n\tfor (; event_n < g.InputEventsQueue.Size; event_n++)\n\t{\n\t\tImGuiInputEvent* e = &g.InputEventsQueue[event_n];\n\t\tif (e->Type == ImGuiInputEventType_MousePos)\n\t\t{\n\t\t\t// Trickling Rule: Stop processing queued events if we already handled a mouse button change\n\t\t\tImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY);\n\t\t\tif (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))\n\t\t\t\tbreak;\n\t\t\tio.MousePos = event_pos;\n\t\t\tio.MouseSource = e->MousePos.MouseSource;\n\t\t\tmouse_moved = true;\n\t\t}\n\t\telse if (e->Type == ImGuiInputEventType_MouseButton)\n\t\t{\n\t\t\t// Trickling Rule: Stop processing queued events if we got multiple action on the same button\n\t\t\tconst ImGuiMouseButton button = e->MouseButton.Button;\n\t\t\tIM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);\n\t\t\tif (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled))\n\t\t\t\tbreak;\n\t\t\tif (trickle_fast_inputs && e->MouseButton.MouseSource == ImGuiMouseSource_TouchScreen && mouse_moved) // #2702: TouchScreen have no initial hover.\n\t\t\t\tbreak;\n\t\t\tio.MouseDown[button] = e->MouseButton.Down;\n\t\t\tio.MouseSource = e->MouseButton.MouseSource;\n\t\t\tmouse_button_changed |= (1 << button);\n\t\t}\n\t\telse if (e->Type == ImGuiInputEventType_MouseWheel)\n\t\t{\n\t\t\t// Trickling Rule: Stop processing queued events if we got multiple action on the event\n\t\t\tif (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))\n\t\t\t\tbreak;\n\t\t\tio.MouseWheelH += e->MouseWheel.WheelX;\n\t\t\tio.MouseWheel += e->MouseWheel.WheelY;\n\t\t\tio.MouseSource = e->MouseWheel.MouseSource;\n\t\t\tmouse_wheeled = true;\n\t\t}\n\t\telse if (e->Type == ImGuiInputEventType_Key)\n\t\t{\n\t\t\t// Trickling Rule: Stop processing queued events if we got multiple action on the same button\n\t\t\tImGuiKey key = e->Key.Key;\n\t\t\tIM_ASSERT(key != ImGuiKey_None);\n\t\t\tImGuiKeyData* key_data = GetKeyData(key);\n\t\t\tconst int key_data_index = (int)(key_data - g.IO.KeysData);\n\t\t\tif (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0))\n\t\t\t\tbreak;\n\t\t\tkey_data->Down = e->Key.Down;\n\t\t\tkey_data->AnalogValue = e->Key.AnalogValue;\n\t\t\tkey_changed = true;\n\t\t\tkey_changed_mask.SetBit(key_data_index);\n\n\t\t\t// Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\t\t\tio.KeysDown[key_data_index] = key_data->Down;\n\t\t\tif (io.KeyMap[key_data_index] != -1)\n\t\t\t\tio.KeysDown[io.KeyMap[key_data_index]] = key_data->Down;\n#endif\n\t\t}\n\t\telse if (e->Type == ImGuiInputEventType_Text)\n\t\t{\n\t\t\t// Trickling Rule: Stop processing queued events if keys/mouse have been interacted with\n\t\t\tif (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))\n\t\t\t\tbreak;\n\t\t\tunsigned int c = e->Text.Char;\n\t\t\tio.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);\n\t\t\tif (trickle_interleaved_keys_and_text)\n\t\t\t\ttext_inputted = true;\n\t\t}\n\t\telse if (e->Type == ImGuiInputEventType_Focus)\n\t\t{\n\t\t\t// We intentionally overwrite this and process in NewFrame(), in order to give a chance\n\t\t\t// to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame.\n\t\t\tconst bool focus_lost = !e->AppFocused.Focused;\n\t\t\tio.AppFocusLost = focus_lost;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIM_ASSERT(0 && \"Unknown event!\");\n\t\t}\n\t}\n\n\t// Record trail (for domain-specific applications wanting to access a precise trail)\n\t//if (event_n != 0) IMGUI_DEBUG_LOG_IO(\"Processed: %d / Remaining: %d\\n\", event_n, g.InputEventsQueue.Size - event_n);\n\tfor (int n = 0; n < event_n; n++)\n\t\tg.InputEventsTrail.push_back(g.InputEventsQueue[n]);\n\n\t// [DEBUG]\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\tif (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO))\n\t\tfor (int n = 0; n < g.InputEventsQueue.Size; n++)\n\t\t\tDebugPrintInputEvent(n < event_n ? \"Processed\" : \"Remaining\", &g.InputEventsQueue[n]);\n#endif\n\n\t// Remaining events will be processed on the next frame\n\tif (event_n == g.InputEventsQueue.Size)\n\t\tg.InputEventsQueue.resize(0);\n\telse\n\t\tg.InputEventsQueue.erase(g.InputEventsQueue.Data, g.InputEventsQueue.Data + event_n);\n\n\t// Clear buttons state when focus is lost\n\t// - this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle.\n\t// - we clear in EndFrame() and not now in order allow application/user code polling this flag\n\t//   (e.g. custom backend may want to clear additional data, custom widgets may want to react with a \"canceling\" event).\n\tif (g.IO.AppFocusLost)\n\t\tg.IO.ClearInputKeys();\n}\n\nImGuiID ImGui::GetKeyOwner(ImGuiKey key)\n{\n\tif (!IsNamedKeyOrModKey(key))\n\t\treturn ImGuiKeyOwner_None;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);\n\tImGuiID owner_id = owner_data->OwnerCurr;\n\n\tif (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)\n\t\tif (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)\n\t\t\treturn ImGuiKeyOwner_None;\n\n\treturn owner_id;\n}\n\n// TestKeyOwner(..., ID)   : (owner == None || owner == ID)\n// TestKeyOwner(..., None) : (owner == None)\n// TestKeyOwner(..., Any)  : no owner test\n// All paths are also testing for key not being locked, for the rare cases that key have been locked with using ImGuiInputFlags_LockXXX flags.\nbool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)\n{\n\tif (!IsNamedKeyOrModKey(key))\n\t\treturn true;\n\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)\n\t\tif (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)\n\t\t\treturn false;\n\n\tImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);\n\tif (owner_id == ImGuiKeyOwner_Any)\n\t\treturn (owner_data->LockThisFrame == false);\n\n\t// Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId\n\t// are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things.\n\t// Setting OwnerCurr in SetKeyOwner() is more consistent than testing OwnerNext here: would be inconsistent with getter and other functions.\n\tif (owner_data->OwnerCurr != owner_id)\n\t{\n\t\tif (owner_data->LockThisFrame)\n\t\t\treturn false;\n\t\tif (owner_data->OwnerCurr != ImGuiKeyOwner_None)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// _LockXXX flags are useful to lock keys away from code which is not input-owner aware.\n// When using _LockXXX flags, you can use ImGuiKeyOwner_Any to lock keys from everyone.\n// - SetKeyOwner(..., None)              : clears owner\n// - SetKeyOwner(..., Any, !Lock)        : illegal (assert)\n// - SetKeyOwner(..., Any or None, Lock) : set lock\nvoid ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tIM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)\n\tIM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function!\n\n\tImGuiContext& g = *GImGui;\n\tImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);\n\towner_data->OwnerCurr = owner_data->OwnerNext = owner_id;\n\n\t// We cannot lock by default as it would likely break lots of legacy code.\n\t// In the case of using LockUntilRelease while key is not down we still lock during the frame (no key_data->Down test)\n\towner_data->LockUntilRelease = (flags & ImGuiInputFlags_LockUntilRelease) != 0;\n\towner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease);\n}\n\n// Rarely used helper\nvoid ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tif (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); }\n\tif (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); }\n\tif (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); }\n\tif (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); }\n\tif (key_chord & ImGuiMod_Shortcut) { SetKeyOwner(ImGuiMod_Shortcut, owner_id, flags); }\n\tif (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); }\n}\n\n// This is more or less equivalent to:\n//   if (IsItemHovered() || IsItemActive())\n//       SetKeyOwner(key, GetItemID());\n// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times.\n// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition.\n// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority.\nvoid ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiID id = g.LastItemData.ID;\n\tif (id == 0 || (g.HoveredId != id && g.ActiveId != id))\n\t\treturn;\n\tif ((flags & ImGuiInputFlags_CondMask_) == 0)\n\t\tflags |= ImGuiInputFlags_CondDefault_;\n\tif ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive)))\n\t{\n\t\tIM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function!\n\t\tSetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_);\n\t}\n}\n\nbool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.\n\tif ((flags & ImGuiInputFlags_RouteMask_) == 0)\n\t\tflags |= ImGuiInputFlags_RouteFocused;\n\tif (!SetShortcutRouting(key_chord, owner_id, flags))\n\t\treturn false;\n\n\tif (key_chord & ImGuiMod_Shortcut)\n\t\tkey_chord = ConvertShortcutMod(key_chord);\n\tImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);\n\tif (g.IO.KeyMods != mods)\n\t\treturn false;\n\n\t// Special storage location for mods\n\tImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);\n\tif (key == ImGuiKey_None)\n\t\tkey = ConvertSingleModFlagToKey(&g, mods);\n\n\tif (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_))))\n\t\treturn false;\n\tIM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function!\n\n\treturn true;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ERROR CHECKING\n//-----------------------------------------------------------------------------\n\n// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.\n// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit\n// If this triggers you have an issue:\n// - Most commonly: mismatched headers and compiled code version.\n// - Or: mismatched configuration #define, compilation settings, packing pragma etc.\n//   The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui,\n//   which is way it is required you put them in your imconfig file (and not just before including imgui.h).\n//   Otherwise it is possible that different compilation units would see different structure layout\nbool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)\n{\n\tbool error = false;\n\tif (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && \"Mismatched version string!\"); }\n\tif (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && \"Mismatched struct layout!\"); }\n\tif (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && \"Mismatched struct layout!\"); }\n\tif (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && \"Mismatched struct layout!\"); }\n\tif (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && \"Mismatched struct layout!\"); }\n\tif (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && \"Mismatched struct layout!\"); }\n\tif (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && \"Mismatched struct layout!\"); }\n\treturn !error;\n}\n\n// Until 1.89 (IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos() to extend the boundary of a parent (e.g. window or table cell)\n// This is causing issues and ambiguity and we need to retire that.\n// See https://github.com/ocornut/imgui/issues/5548 for more details.\n// [Scenario 1]\n//  Previously this would make the window content size ~200x200:\n//    Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();  // NOT OK\n//  Instead, please submit an item:\n//    Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK\n//  Alternative:\n//    Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK\n// [Scenario 2]\n//  For reference this is one of the issue what we aim to fix with this change:\n//    BeginGroup() + SomeItem(\"foobar\") + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup()\n//  The previous logic made SetCursorScreenPos(GetCursorScreenPos()) have a side-effect! It would erroneously incorporate ItemSpacing.y after the item into content size, making the group taller!\n//  While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. Using vertical alignment patterns could trigger this issue.\nvoid ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(window->DC.IsSetPos);\n\twindow->DC.IsSetPos = false;\n#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tif (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y)\n\t\treturn;\n\tif (window->SkipItems)\n\t\treturn;\n\tIM_ASSERT(0 && \"Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. Please submit an item e.g. Dummy() to validate extent.\");\n#else\n\twindow->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);\n#endif\n}\n\nstatic void ImGui::ErrorCheckNewFrameSanityChecks()\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Check user IM_ASSERT macro\n\t// (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined!\n\t//  If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.\n\t//  This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)\n\t// #define IM_ASSERT(EXPR)   if (SomeCode(EXPR)) SomeMoreCode();                    // Wrong!\n\t// #define IM_ASSERT(EXPR)   do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0)   // Correct!\n\tif (true) IM_ASSERT(1); else IM_ASSERT(0);\n\n\t// Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644)\n\t// Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it.\n#ifdef __EMSCRIPTEN__\n\tif (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0)\n\t\tg.IO.DeltaTime = 0.00001f;\n#endif\n\n\t// Check user data\n\t// (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)\n\tIM_ASSERT(g.Initialized);\n\tIM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && \"Need a positive DeltaTime!\");\n\tIM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && \"Forgot to call Render() or EndFrame() at the end of the previous frame?\");\n\tIM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && \"Invalid DisplaySize value!\");\n\tIM_ASSERT(g.IO.Fonts->IsBuilt() && \"Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()\");\n\tIM_ASSERT(g.Style.CurveTessellationTol > 0.0f && \"Invalid style setting!\");\n\tIM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && \"Invalid style setting!\");\n\tIM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && \"Invalid style setting!\"); // Allows us to avoid a few clamps in color computations\n\tIM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && \"Invalid style setting.\");\n\tIM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);\n\tIM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right);\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tfor (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++)\n\t\tIM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && \"io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)\");\n\n\t// Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP)\n\tif ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1)\n\t\tIM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && \"ImGuiKey_Space is not mapped, required for keyboard navigation.\");\n#endif\n\n\t// Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.\n\tif (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))\n\t\tg.IO.ConfigWindowsResizeFromEdges = false;\n}\n\nstatic void ImGui::ErrorCheckEndFrameSanityChecks()\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()\n\t// One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().\n\t// It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will\n\t// send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.\n\t// We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),\n\t// while still correctly asserting on mid-frame key press events.\n\tconst ImGuiKeyChord key_mods = GetMergedModsFromKeys();\n\tIM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && \"Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods\");\n\tIM_UNUSED(key_mods);\n\n\t// [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame().\n\t//ErrorCheckEndFrameRecover();\n\n\t// Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you\n\t// to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).\n\tif (g.CurrentWindowStack.Size != 1)\n\t{\n\t\tif (g.CurrentWindowStack.Size > 1)\n\t\t{\n\t\t\tImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended!\n\t\t\tIM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, \"Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?\");\n\t\t\tIM_UNUSED(window);\n\t\t\twhile (g.CurrentWindowStack.Size > 1)\n\t\t\t\tEnd();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, \"Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?\");\n\t\t}\n\t}\n\n\tIM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, \"Missing EndGroup call!\");\n}\n\n// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.\n// Must be called during or before EndFrame().\n// This is generally flawed as we are not necessarily End/Popping things in the right order.\n// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.\n// FIXME: Can't recover from interleaved BeginTabBar/Begin\nvoid    ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data)\n{\n\t// PVS-Studio V1044 is \"Loop break conditions do not depend on the number of iterations\"\n\tImGuiContext& g = *GImGui;\n\twhile (g.CurrentWindowStack.Size > 0) //-V1044\n\t{\n\t\tErrorCheckEndWindowRecover(log_callback, user_data);\n\t\tImGuiWindow* window = g.CurrentWindow;\n\t\tif (g.CurrentWindowStack.Size == 1)\n\t\t{\n\t\t\tIM_ASSERT(window->IsFallbackWindow);\n\t\t\tbreak;\n\t\t}\n\t\tif (window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\t{\n\t\t\tif (log_callback) log_callback(user_data, \"Recovered from missing EndChild() for '%s'\", window->Name);\n\t\t\tEndChild();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (log_callback) log_callback(user_data, \"Recovered from missing End() for '%s'\", window->Name);\n\t\t\tEnd();\n\t\t}\n\t}\n}\n\n// Must be called before End()/EndChild()\nvoid    ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data)\n{\n\tImGuiContext& g = *GImGui;\n\twhile (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing EndTable() in '%s'\", g.CurrentTable->OuterWindow->Name);\n\t\tEndTable();\n\t}\n\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin;\n\tIM_ASSERT(window != NULL);\n\twhile (g.CurrentTabBar != NULL) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing EndTabBar() in '%s'\", window->Name);\n\t\tEndTabBar();\n\t}\n\twhile (window->DC.TreeDepth > 0)\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing TreePop() in '%s'\", window->Name);\n\t\tTreePop();\n\t}\n\twhile (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing EndGroup() in '%s'\", window->Name);\n\t\tEndGroup();\n\t}\n\twhile (window->IDStack.Size > 1)\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopID() in '%s'\", window->Name);\n\t\tPopID();\n\t}\n\twhile (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing EndDisabled() in '%s'\", window->Name);\n\t\tEndDisabled();\n\t}\n\twhile (g.ColorStack.Size > stack_sizes->SizeOfColorStack)\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s\", window->Name, GetStyleColorName(g.ColorStack.back().Col));\n\t\tPopStyleColor();\n\t}\n\twhile (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopItemFlag() in '%s'\", window->Name);\n\t\tPopItemFlag();\n\t}\n\twhile (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopStyleVar() in '%s'\", window->Name);\n\t\tPopStyleVar();\n\t}\n\twhile (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopFont() in '%s'\", window->Name);\n\t\tPopFont();\n\t}\n\twhile (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044\n\t{\n\t\tif (log_callback) log_callback(user_data, \"Recovered from missing PopFocusScope() in '%s'\", window->Name);\n\t\tPopFocusScope();\n\t}\n}\n\n// Save current stack sizes for later compare\nvoid ImGuiStackSizes::SetToContextState(ImGuiContext* ctx)\n{\n\tImGuiContext& g = *ctx;\n\tImGuiWindow* window = g.CurrentWindow;\n\tSizeOfIDStack = (short)window->IDStack.Size;\n\tSizeOfColorStack = (short)g.ColorStack.Size;\n\tSizeOfStyleVarStack = (short)g.StyleVarStack.Size;\n\tSizeOfFontStack = (short)g.FontStack.Size;\n\tSizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;\n\tSizeOfGroupStack = (short)g.GroupStack.Size;\n\tSizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size;\n\tSizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;\n\tSizeOfDisabledStack = (short)g.DisabledStackSize;\n}\n\n// Compare to detect usage errors\nvoid ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx)\n{\n\tImGuiContext& g = *ctx;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_UNUSED(window);\n\n\t// Window stacks\n\t// NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)\n\tIM_ASSERT(SizeOfIDStack == window->IDStack.Size && \"PushID/PopID or TreeNode/TreePop Mismatch!\");\n\n\t// Global stacks\n\t// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.\n\tIM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && \"BeginGroup/EndGroup Mismatch!\");\n\tIM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && \"BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!\");\n\tIM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && \"BeginDisabled/EndDisabled Mismatch!\");\n\tIM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && \"PushItemFlag/PopItemFlag Mismatch!\");\n\tIM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && \"PushStyleColor/PopStyleColor Mismatch!\");\n\tIM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && \"PushStyleVar/PopStyleVar Mismatch!\");\n\tIM_ASSERT(SizeOfFontStack >= g.FontStack.Size && \"PushFont/PopFont Mismatch!\");\n\tIM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && \"PushFocusScope/PopFocusScope Mismatch!\");\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] LAYOUT\n//-----------------------------------------------------------------------------\n// - ItemSize()\n// - ItemAdd()\n// - SameLine()\n// - GetCursorScreenPos()\n// - SetCursorScreenPos()\n// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()\n// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()\n// - GetCursorStartPos()\n// - Indent()\n// - Unindent()\n// - SetNextItemWidth()\n// - PushItemWidth()\n// - PushMultiItemsWidths()\n// - PopItemWidth()\n// - CalcItemWidth()\n// - CalcItemSize()\n// - GetTextLineHeight()\n// - GetTextLineHeightWithSpacing()\n// - GetFrameHeight()\n// - GetFrameHeightWithSpacing()\n// - GetContentRegionMax()\n// - GetContentRegionMaxAbs() [Internal]\n// - GetContentRegionAvail(),\n// - GetWindowContentRegionMin(), GetWindowContentRegionMax()\n// - BeginGroup()\n// - EndGroup()\n// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns.\n//-----------------------------------------------------------------------------\n\n// Advance cursor given item size for layout.\n// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.\n// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.\nvoid ImGui::ItemSize(const ImVec2& size, float text_baseline_y)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\t// We increase the height in this function to accommodate for baseline offset.\n\t// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,\n\t// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.\n\tconst float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;\n\n\tconst float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y;\n\tconst float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y);\n\n\t// Always align ourselves on pixel boundaries\n\t//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]\n\twindow->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;\n\twindow->DC.CursorPosPrevLine.y = line_y1;\n\twindow->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);    // Next line\n\twindow->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y);                       // Next line\n\twindow->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);\n\twindow->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);\n\t//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]\n\n\twindow->DC.PrevLineSize.y = line_height;\n\twindow->DC.CurrLineSize.y = 0.0f;\n\twindow->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);\n\twindow->DC.CurrLineTextBaseOffset = 0.0f;\n\twindow->DC.IsSameLine = window->DC.IsSetPos = false;\n\n\t// Horizontal layout mode\n\tif (window->DC.LayoutType == ImGuiLayoutType_Horizontal)\n\t\tSameLine();\n}\n\n// Declare item bounding box for clipping and interaction.\n// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface\n// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.\nbool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// Set item data\n\t// (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set)\n\tg.LastItemData.ID = id;\n\tg.LastItemData.Rect = bb;\n\tg.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb;\n\tg.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags;\n\tg.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;\n\n\t// Directional navigation processing\n\tif (id != 0)\n\t{\n\t\tKeepAliveID(id);\n\n\t\t// Runs prior to clipping early-out\n\t\t//  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget\n\t\t//  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests\n\t\t//      unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of\n\t\t//      thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.\n\t\t//      We could early out with \"if (is_clipped && !g.NavInitRequest) return false;\" but when we wouldn't be able\n\t\t//      to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).\n\t\t// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.\n\t\t// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.\n\t\tif (!(g.LastItemData.InFlags & ImGuiItemFlags_NoNav))\n\t\t{\n\t\t\twindow->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);\n\t\t\tif (g.NavId == id || g.NavAnyRequest)\n\t\t\t\tif (g.NavWindow->RootWindowForNav == window->RootWindowForNav)\n\t\t\t\t\tif (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))\n\t\t\t\t\t\tNavProcessItem();\n\t\t}\n\n\t\t// [DEBUG] People keep stumbling on this problem and using \"\" as identifier in the root of a window instead of \"##something\".\n\t\t// Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use \"##something\".\n\t\t// READ THE FAQ: https://dearimgui.com/faq\n\t\tIM_ASSERT(id != window->ID && \"Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!\");\n\t}\n\tg.NextItemData.Flags = ImGuiNextItemDataFlags_None;\n\tg.NextItemData.ItemFlags = ImGuiItemFlags_None;\n\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\tif (id != 0)\n\t\tIMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData);\n#endif\n\n\t// Clipping test\n\t// (FIXME: This is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value)\n\t//const bool is_clipped = IsClippedEx(bb, id);\n\t//if (is_clipped)\n\t//    return false;\n\tconst bool is_rect_visible = bb.Overlaps(window->ClipRect);\n\tif (!is_rect_visible)\n\t\tif (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId))\n\t\t\tif (!g.LogEnabled)\n\t\t\t\treturn false;\n\n\t// [DEBUG]\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\tif (id != 0 && id == g.DebugLocateId)\n\t\tDebugLocateItemResolveWithLastItem();\n#endif\n\t//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]\n\t//if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0)\n\t//    window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG]\n\n\t// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)\n\tif (is_rect_visible)\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Visible;\n\tif (IsMouseHoveringRect(bb.Min, bb.Max))\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;\n\treturn true;\n}\n\n// Gets back to previous line and continue with horizontal layout\n//      offset_from_start_x == 0 : follow right after previous item\n//      offset_from_start_x != 0 : align to specified x position (relative to window/group left)\n//      spacing_w < 0            : use default spacing if offset_from_start_x == 0, no spacing if offset_from_start_x != 0\n//      spacing_w >= 0           : enforce spacing amount\nvoid ImGui::SameLine(float offset_from_start_x, float spacing_w)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\tif (offset_from_start_x != 0.0f)\n\t{\n\t\tif (spacing_w < 0.0f)\n\t\t\tspacing_w = 0.0f;\n\t\twindow->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;\n\t\twindow->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;\n\t}\n\telse\n\t{\n\t\tif (spacing_w < 0.0f)\n\t\t\tspacing_w = g.Style.ItemSpacing.x;\n\t\twindow->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;\n\t\twindow->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;\n\t}\n\twindow->DC.CurrLineSize = window->DC.PrevLineSize;\n\twindow->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;\n\twindow->DC.IsSameLine = true;\n}\n\nImVec2 ImGui::GetCursorScreenPos()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CursorPos;\n}\n\nvoid ImGui::SetCursorScreenPos(const ImVec2& pos)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.CursorPos = pos;\n\t//window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);\n\twindow->DC.IsSetPos = true;\n}\n\n// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.\n// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.\nImVec2 ImGui::GetCursorPos()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CursorPos - window->Pos + window->Scroll;\n}\n\nfloat ImGui::GetCursorPosX()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;\n}\n\nfloat ImGui::GetCursorPosY()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;\n}\n\nvoid ImGui::SetCursorPos(const ImVec2& local_pos)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.CursorPos = window->Pos - window->Scroll + local_pos;\n\t//window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);\n\twindow->DC.IsSetPos = true;\n}\n\nvoid ImGui::SetCursorPosX(float x)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;\n\t//window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);\n\twindow->DC.IsSetPos = true;\n}\n\nvoid ImGui::SetCursorPosY(float y)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;\n\t//window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);\n\twindow->DC.IsSetPos = true;\n}\n\nImVec2 ImGui::GetCursorStartPos()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CursorStartPos - window->Pos;\n}\n\nvoid ImGui::Indent(float indent_w)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;\n\twindow->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;\n}\n\nvoid ImGui::Unindent(float indent_w)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;\n\twindow->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;\n}\n\n// Affect large frame+labels widgets only.\nvoid ImGui::SetNextItemWidth(float item_width)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;\n\tg.NextItemData.Width = item_width;\n}\n\n// FIXME: Remove the == 0.0f behavior?\nvoid ImGui::PushItemWidth(float item_width)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\twindow->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width\n\twindow->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);\n\tg.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;\n}\n\nvoid ImGui::PushMultiItemsWidths(int components, float w_full)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tconst ImGuiStyle& style = g.Style;\n\tconst float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));\n\tconst float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));\n\twindow->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width\n\twindow->DC.ItemWidthStack.push_back(w_item_last);\n\tfor (int i = 0; i < components - 2; i++)\n\t\twindow->DC.ItemWidthStack.push_back(w_item_one);\n\twindow->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one;\n\tg.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;\n}\n\nvoid ImGui::PopItemWidth()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\twindow->DC.ItemWidth = window->DC.ItemWidthStack.back();\n\twindow->DC.ItemWidthStack.pop_back();\n}\n\n// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().\n// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()\nfloat ImGui::CalcItemWidth()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tfloat w;\n\tif (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)\n\t\tw = g.NextItemData.Width;\n\telse\n\t\tw = window->DC.ItemWidth;\n\tif (w < 0.0f)\n\t{\n\t\tfloat region_max_x = GetContentRegionMaxAbs().x;\n\t\tw = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);\n\t}\n\tw = IM_FLOOR(w);\n\treturn w;\n}\n\n// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().\n// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.\n// Note that only CalcItemWidth() is publicly exposed.\n// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)\nImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tImVec2 region_max;\n\tif (size.x < 0.0f || size.y < 0.0f)\n\t\tregion_max = GetContentRegionMaxAbs();\n\n\tif (size.x == 0.0f)\n\t\tsize.x = default_w;\n\telse if (size.x < 0.0f)\n\t\tsize.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);\n\n\tif (size.y == 0.0f)\n\t\tsize.y = default_h;\n\telse if (size.y < 0.0f)\n\t\tsize.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);\n\n\treturn size;\n}\n\nfloat ImGui::GetTextLineHeight()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize;\n}\n\nfloat ImGui::GetTextLineHeightWithSpacing()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize + g.Style.ItemSpacing.y;\n}\n\nfloat ImGui::GetFrameHeight()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize + g.Style.FramePadding.y * 2.0f;\n}\n\nfloat ImGui::GetFrameHeightWithSpacing()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;\n}\n\n// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW \"WORK RECT\" API. Thanks for your patience!\n\n// FIXME: This is in window space (not screen space!).\nImVec2 ImGui::GetContentRegionMax()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max;\n\treturn mx - window->Pos;\n}\n\n// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.\nImVec2 ImGui::GetContentRegionMaxAbs()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max;\n\treturn mx;\n}\n\nImVec2 ImGui::GetContentRegionAvail()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn GetContentRegionMaxAbs() - window->DC.CursorPos;\n}\n\n// In window space (not screen space!)\nImVec2 ImGui::GetWindowContentRegionMin()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ContentRegionRect.Min - window->Pos;\n}\n\nImVec2 ImGui::GetWindowContentRegionMax()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ContentRegionRect.Max - window->Pos;\n}\n\n// Lock horizontal starting position + capture group bounding box into one \"item\" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)\n// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.\n// FIXME-OPT: Could we safely early out on ->SkipItems?\nvoid ImGui::BeginGroup()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tg.GroupStack.resize(g.GroupStack.Size + 1);\n\tImGuiGroupData& group_data = g.GroupStack.back();\n\tgroup_data.WindowID = window->ID;\n\tgroup_data.BackupCursorPos = window->DC.CursorPos;\n\tgroup_data.BackupCursorMaxPos = window->DC.CursorMaxPos;\n\tgroup_data.BackupIndent = window->DC.Indent;\n\tgroup_data.BackupGroupOffset = window->DC.GroupOffset;\n\tgroup_data.BackupCurrLineSize = window->DC.CurrLineSize;\n\tgroup_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;\n\tgroup_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;\n\tgroup_data.BackupHoveredIdIsAlive = g.HoveredId != 0;\n\tgroup_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;\n\tgroup_data.EmitItem = true;\n\n\twindow->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;\n\twindow->DC.Indent = window->DC.GroupOffset;\n\twindow->DC.CursorMaxPos = window->DC.CursorPos;\n\twindow->DC.CurrLineSize = ImVec2(0.0f, 0.0f);\n\tif (g.LogEnabled)\n\t\tg.LogLinePosY = -FLT_MAX; // To enforce a carriage return\n}\n\nvoid ImGui::EndGroup()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls\n\n\tImGuiGroupData& group_data = g.GroupStack.back();\n\tIM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window?\n\n\tif (window->DC.IsSetPos)\n\t\tErrorCheckUsingSetCursorPosToExtendParentBoundaries();\n\n\tImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));\n\n\twindow->DC.CursorPos = group_data.BackupCursorPos;\n\twindow->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);\n\twindow->DC.Indent = group_data.BackupIndent;\n\twindow->DC.GroupOffset = group_data.BackupGroupOffset;\n\twindow->DC.CurrLineSize = group_data.BackupCurrLineSize;\n\twindow->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;\n\tif (g.LogEnabled)\n\t\tg.LogLinePosY = -FLT_MAX; // To enforce a carriage return\n\n\tif (!group_data.EmitItem)\n\t{\n\t\tg.GroupStack.pop_back();\n\t\treturn;\n\t}\n\n\twindow->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset);      // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.\n\tItemSize(group_bb.GetSize());\n\tItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);\n\n\t// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.\n\t// It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.\n\t// Also if you grep for LastItemId you'll notice it is only used in that context.\n\t// (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)\n\tconst bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;\n\tconst bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);\n\tif (group_contains_curr_active_id)\n\t\tg.LastItemData.ID = g.ActiveId;\n\telse if (group_contains_prev_active_id)\n\t\tg.LastItemData.ID = g.ActiveIdPreviousFrame;\n\tg.LastItemData.Rect = group_bb;\n\n\t// Forward Hovered flag\n\tconst bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;\n\tif (group_contains_curr_hovered_id)\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;\n\n\t// Forward Edited flag\n\tif (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;\n\n\t// Forward Deactivated flag\n\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated;\n\tif (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated;\n\n\tg.GroupStack.pop_back();\n\t//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] SCROLLING\n//-----------------------------------------------------------------------------\n\n// Helper to snap on edges when aiming at an item very close to the edge,\n// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.\n// When we refactor the scrolling API this may be configurable with a flag?\n// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.\nstatic float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)\n{\n\tif (target <= snap_min + snap_threshold)\n\t\treturn ImLerp(snap_min, target, center_ratio);\n\tif (target >= snap_max - snap_threshold)\n\t\treturn ImLerp(target, snap_max, center_ratio);\n\treturn target;\n}\n\nstatic ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)\n{\n\tImVec2 scroll = window->Scroll;\n\tImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2);\n\tfor (int axis = 0; axis < 2; axis++)\n\t{\n\t\tif (window->ScrollTarget[axis] < FLT_MAX)\n\t\t{\n\t\t\tfloat center_ratio = window->ScrollTargetCenterRatio[axis];\n\t\t\tfloat scroll_target = window->ScrollTarget[axis];\n\t\t\tif (window->ScrollTargetEdgeSnapDist[axis] > 0.0f)\n\t\t\t{\n\t\t\t\tfloat snap_min = 0.0f;\n\t\t\t\tfloat snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis];\n\t\t\t\tscroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio);\n\t\t\t}\n\t\t\tscroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]);\n\t\t}\n\t\tscroll[axis] = IM_FLOOR(ImMax(scroll[axis], 0.0f));\n\t\tif (!window->Collapsed && !window->SkipItems)\n\t\t\tscroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]);\n\t}\n\treturn scroll;\n}\n\nvoid ImGui::ScrollToItem(ImGuiScrollFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tScrollToRectEx(window, g.LastItemData.NavRect, flags);\n}\n\nvoid ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)\n{\n\tScrollToRectEx(window, item_rect, flags);\n}\n\n// Scroll to keep newly navigated item fully into view\nImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));\n\tscroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x);\n\tscroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y);\n\t//GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG]\n\t//GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG]\n\n\t// Check that only one behavior is selected per axis\n\tIM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_));\n\tIM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_));\n\n\t// Defaults\n\tImGuiScrollFlags in_flags = flags;\n\tif ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX)\n\t\tflags |= ImGuiScrollFlags_KeepVisibleEdgeX;\n\tif ((flags & ImGuiScrollFlags_MaskY_) == 0)\n\t\tflags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY;\n\n\tconst bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x;\n\tconst bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y;\n\tconst bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;\n\tconst bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;\n\n\tif ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)\n\t{\n\t\tif (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x)\n\t\t\tSetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f);\n\t\telse if (item_rect.Max.x >= scroll_rect.Max.x)\n\t\t\tSetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f);\n\t}\n\telse if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX))\n\t{\n\t\tif (can_be_fully_visible_x)\n\t\t\tSetScrollFromPosX(window, ImFloor((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f);\n\t\telse\n\t\t\tSetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f);\n\t}\n\n\tif ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y)\n\t{\n\t\tif (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y)\n\t\t\tSetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f);\n\t\telse if (item_rect.Max.y >= scroll_rect.Max.y)\n\t\t\tSetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f);\n\t}\n\telse if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY))\n\t{\n\t\tif (can_be_fully_visible_y)\n\t\t\tSetScrollFromPosY(window, ImFloor((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f);\n\t\telse\n\t\t\tSetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f);\n\t}\n\n\tImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);\n\tImVec2 delta_scroll = next_scroll - window->Scroll;\n\n\t// Also scroll parent window to keep us into view if necessary\n\tif (!(flags & ImGuiScrollFlags_NoScrollParent) && (window->Flags & ImGuiWindowFlags_ChildWindow))\n\t{\n\t\t// FIXME-SCROLL: May be an option?\n\t\tif ((in_flags & (ImGuiScrollFlags_AlwaysCenterX | ImGuiScrollFlags_KeepVisibleCenterX)) != 0)\n\t\t\tin_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX;\n\t\tif ((in_flags & (ImGuiScrollFlags_AlwaysCenterY | ImGuiScrollFlags_KeepVisibleCenterY)) != 0)\n\t\t\tin_flags = (in_flags & ~ImGuiScrollFlags_MaskY_) | ImGuiScrollFlags_KeepVisibleEdgeY;\n\t\tdelta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags);\n\t}\n\n\treturn delta_scroll;\n}\n\nfloat ImGui::GetScrollX()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->Scroll.x;\n}\n\nfloat ImGui::GetScrollY()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->Scroll.y;\n}\n\nfloat ImGui::GetScrollMaxX()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ScrollMax.x;\n}\n\nfloat ImGui::GetScrollMaxY()\n{\n\tImGuiWindow* window = GImGui->CurrentWindow;\n\treturn window->ScrollMax.y;\n}\n\nvoid ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)\n{\n\twindow->ScrollTarget.x = scroll_x;\n\twindow->ScrollTargetCenterRatio.x = 0.0f;\n\twindow->ScrollTargetEdgeSnapDist.x = 0.0f;\n}\n\nvoid ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)\n{\n\twindow->ScrollTarget.y = scroll_y;\n\twindow->ScrollTargetCenterRatio.y = 0.0f;\n\twindow->ScrollTargetEdgeSnapDist.y = 0.0f;\n}\n\nvoid ImGui::SetScrollX(float scroll_x)\n{\n\tImGuiContext& g = *GImGui;\n\tSetScrollX(g.CurrentWindow, scroll_x);\n}\n\nvoid ImGui::SetScrollY(float scroll_y)\n{\n\tImGuiContext& g = *GImGui;\n\tSetScrollY(g.CurrentWindow, scroll_y);\n}\n\n// Note that a local position will vary depending on initial scroll value,\n// This is a little bit confusing so bear with us:\n//  - local_pos = (absolution_pos - window->Pos)\n//  - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,\n//    and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.\n//  - They mostly exist because of legacy API.\n// Following the rules above, when trying to work with scrolling code, consider that:\n//  - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!\n//  - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense\n// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size\nvoid ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)\n{\n\tIM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);\n\twindow->ScrollTarget.x = IM_FLOOR(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset\n\twindow->ScrollTargetCenterRatio.x = center_x_ratio;\n\twindow->ScrollTargetEdgeSnapDist.x = 0.0f;\n}\n\nvoid ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)\n{\n\tIM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);\n\twindow->ScrollTarget.y = IM_FLOOR(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset\n\twindow->ScrollTargetCenterRatio.y = center_y_ratio;\n\twindow->ScrollTargetEdgeSnapDist.y = 0.0f;\n}\n\nvoid ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)\n{\n\tImGuiContext& g = *GImGui;\n\tSetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);\n}\n\nvoid ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)\n{\n\tImGuiContext& g = *GImGui;\n\tSetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);\n}\n\n// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.\nvoid ImGui::SetScrollHereX(float center_x_ratio)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tfloat spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);\n\tfloat target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio);\n\tSetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos\n\n\t// Tweak: snap on edges when aiming at an item very close to the edge\n\twindow->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);\n}\n\n// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.\nvoid ImGui::SetScrollHereY(float center_y_ratio)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tfloat spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y);\n\tfloat target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);\n\tSetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos\n\n\t// Tweak: snap on edges when aiming at an item very close to the edge\n\twindow->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] TOOLTIPS\n//-----------------------------------------------------------------------------\n\nbool ImGui::BeginTooltip()\n{\n\treturn BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None);\n}\n\nbool ImGui::BeginItemTooltip()\n{\n\tif (!IsItemHovered(ImGuiHoveredFlags_ForTooltip))\n\t\treturn false;\n\treturn BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None);\n}\n\nbool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\tif (g.DragDropWithinSource || g.DragDropWithinTarget)\n\t{\n\t\t// Drag and Drop tooltips are positioning differently than other tooltips:\n\t\t// - offset visibility to increase visibility around mouse.\n\t\t// - never clamp within outer viewport boundary.\n\t\t// We call SetNextWindowPos() to enforce position and disable clamping.\n\t\t// See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones).\n\t\t//ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;\n\t\tImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale;\n\t\tSetNextWindowPos(tooltip_pos);\n\t\tSetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);\n\t\t//PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(\n\t\ttooltip_flags |= ImGuiTooltipFlags_OverridePrevious;\n\t}\n\n\tchar window_name[16];\n\tImFormatString(window_name, IM_ARRAYSIZE(window_name), \"##Tooltip_%02d\", g.TooltipOverrideCount);\n\tif (tooltip_flags & ImGuiTooltipFlags_OverridePrevious)\n\t\tif (ImGuiWindow* window = FindWindowByName(window_name))\n\t\t\tif (window->Active)\n\t\t\t{\n\t\t\t\t// Hide previous tooltip from being displayed. We can't easily \"reset\" the content of a window so we create a new one.\n\t\t\t\tSetWindowHiddendAndSkipItemsForCurrentFrame(window);\n\t\t\t\tImFormatString(window_name, IM_ARRAYSIZE(window_name), \"##Tooltip_%02d\", ++g.TooltipOverrideCount);\n\t\t\t}\n\tImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;\n\tBegin(window_name, NULL, flags | extra_window_flags);\n\t// 2023-03-09: Added bool return value to the API, but currently always returning true.\n\t// If this ever returns false we need to update BeginDragDropSource() accordingly.\n\t//if (!ret)\n\t//    End();\n\t//return ret;\n\treturn true;\n}\n\nvoid ImGui::EndTooltip()\n{\n\tIM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls\n\tEnd();\n}\n\nvoid ImGui::SetTooltip(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tSetTooltipV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::SetTooltipV(const char* fmt, va_list args)\n{\n\tif (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))\n\t\treturn;\n\tTextV(fmt, args);\n\tEndTooltip();\n}\n\n// Shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav'.\n// Defaults to == ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort when using the mouse.\nvoid ImGui::SetItemTooltip(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tif (IsItemHovered(ImGuiHoveredFlags_ForTooltip))\n\t\tSetTooltipV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::SetItemTooltipV(const char* fmt, va_list args)\n{\n\tif (IsItemHovered(ImGuiHoveredFlags_ForTooltip))\n\t\tSetTooltipV(fmt, args);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] POPUPS\n//-----------------------------------------------------------------------------\n\n// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel\nbool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (popup_flags & ImGuiPopupFlags_AnyPopupId)\n\t{\n\t\t// Return true if any popup is open at the current BeginPopup() level of the popup stack\n\t\t// This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.\n\t\tIM_ASSERT(id == 0);\n\t\tif (popup_flags & ImGuiPopupFlags_AnyPopupLevel)\n\t\t\treturn g.OpenPopupStack.Size > 0;\n\t\telse\n\t\t\treturn g.OpenPopupStack.Size > g.BeginPopupStack.Size;\n\t}\n\telse\n\t{\n\t\tif (popup_flags & ImGuiPopupFlags_AnyPopupLevel)\n\t\t{\n\t\t\t// Return true if the popup is open anywhere in the popup stack\n\t\t\tfor (int n = 0; n < g.OpenPopupStack.Size; n++)\n\t\t\t\tif (g.OpenPopupStack[n].PopupId == id)\n\t\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)\n\t\t\treturn g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;\n\t\t}\n\t}\n}\n\nbool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);\n\tif ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)\n\t\tIM_ASSERT(0 && \"Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel.\"); // But non-string version is legal and used internally\n\treturn IsPopupOpen(id, popup_flags);\n}\n\n// Also see FindBlockingModal(NULL)\nImGuiWindow* ImGui::GetTopMostPopupModal()\n{\n\tImGuiContext& g = *GImGui;\n\tfor (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)\n\t\tif (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)\n\t\t\tif (popup->Flags & ImGuiWindowFlags_Modal)\n\t\t\t\treturn popup;\n\treturn NULL;\n}\n\n// See Demo->Stacked Modal to confirm what this is for.\nImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal()\n{\n\tImGuiContext& g = *GImGui;\n\tfor (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)\n\t\tif (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)\n\t\t\tif ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup))\n\t\t\t\treturn popup;\n\treturn NULL;\n}\n\nvoid ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiID id = g.CurrentWindow->GetID(str_id);\n\tIMGUI_DEBUG_LOG_POPUP(\"[popup] OpenPopup(\\\"%s\\\" -> 0x%08X)\\n\", str_id, id);\n\tOpenPopupEx(id, popup_flags);\n}\n\nvoid ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags)\n{\n\tOpenPopupEx(id, popup_flags);\n}\n\n// Mark popup as open (toggle toward open state).\n// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.\n// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).\n// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)\nvoid ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* parent_window = g.CurrentWindow;\n\tconst int current_stack_size = g.BeginPopupStack.Size;\n\n\tif (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)\n\t\tif (IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId))\n\t\t\treturn;\n\n\tImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.\n\tpopup_ref.PopupId = id;\n\tpopup_ref.Window = NULL;\n\tpopup_ref.BackupNavWindow = g.NavWindow;            // When popup closes focus may be restored to NavWindow (depend on window type).\n\tpopup_ref.OpenFrameCount = g.FrameCount;\n\tpopup_ref.OpenParentId = parent_window->IDStack.back();\n\tpopup_ref.OpenPopupPos = NavCalcPreferredRefPos();\n\tpopup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;\n\n\tIMGUI_DEBUG_LOG_POPUP(\"[popup] OpenPopupEx(0x%08X)\\n\", id);\n\tif (g.OpenPopupStack.Size < current_stack_size + 1)\n\t{\n\t\tg.OpenPopupStack.push_back(popup_ref);\n\t}\n\telse\n\t{\n\t\t// Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui\n\t\t// would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing\n\t\t// situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.\n\t\tif (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)\n\t\t{\n\t\t\tg.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Close child popups if any, then flag popup for open/reopen\n\t\t\tClosePopupToLevel(current_stack_size, false);\n\t\t\tg.OpenPopupStack.push_back(popup_ref);\n\t\t}\n\n\t\t// When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().\n\t\t// This is equivalent to what ClosePopupToLevel() does.\n\t\t//if (g.OpenPopupStack[current_stack_size].PopupId == id)\n\t\t//    FocusWindow(parent_window);\n\t}\n}\n\n// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.\n// This function closes any popups that are over 'ref_window'.\nvoid ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.OpenPopupStack.Size == 0)\n\t\treturn;\n\n\t// Don't close our own child popup windows.\n\tint popup_count_to_keep = 0;\n\tif (ref_window)\n\t{\n\t\t// Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)\n\t\tfor (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)\n\t\t{\n\t\t\tImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];\n\t\t\tif (!popup.Window)\n\t\t\t\tcontinue;\n\t\t\tIM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);\n\t\t\tif (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\t\t\tcontinue;\n\n\t\t\t// Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)\n\t\t\t// - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:\n\t\t\t//     Window -> Popup1 -> Popup2 -> Popup3\n\t\t\t// - Each popups may contain child windows, which is why we compare ->RootWindow!\n\t\t\t//     Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child\n\t\t\tbool ref_window_is_descendent_of_popup = false;\n\t\t\tfor (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)\n\t\t\t\tif (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)\n\t\t\t\t\tif (IsWindowWithinBeginStackOf(ref_window, popup_window))\n\t\t\t\t\t{\n\t\t\t\t\t\tref_window_is_descendent_of_popup = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\tif (!ref_window_is_descendent_of_popup)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tif (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below\n\t{\n\t\tIMGUI_DEBUG_LOG_POPUP(\"[popup] ClosePopupsOverWindow(\\\"%s\\\")\\n\", ref_window ? ref_window->Name : \"<NULL>\");\n\t\tClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);\n\t}\n}\n\nvoid ImGui::ClosePopupsExceptModals()\n{\n\tImGuiContext& g = *GImGui;\n\n\tint popup_count_to_keep;\n\tfor (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--)\n\t{\n\t\tImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window;\n\t\tif (!window || (window->Flags & ImGuiWindowFlags_Modal))\n\t\t\tbreak;\n\t}\n\tif (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below\n\t\tClosePopupToLevel(popup_count_to_keep, true);\n}\n\nvoid ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)\n{\n\tImGuiContext& g = *GImGui;\n\tIMGUI_DEBUG_LOG_POPUP(\"[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\\n\", remaining, restore_focus_to_window_under_popup);\n\tIM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);\n\n\t// Trim open popup stack\n\tImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;\n\tImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow;\n\tg.OpenPopupStack.resize(remaining);\n\n\tif (restore_focus_to_window_under_popup)\n\t{\n\t\tImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window;\n\t\tif (focus_window && !focus_window->WasActive && popup_window)\n\t\t\tFocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback\n\t\telse\n\t\t\tFocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None);\n\t}\n}\n\n// Close the popup we have begin-ed into.\nvoid ImGui::CloseCurrentPopup()\n{\n\tImGuiContext& g = *GImGui;\n\tint popup_idx = g.BeginPopupStack.Size - 1;\n\tif (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)\n\t\treturn;\n\n\t// Closing a menu closes its top-most parent popup (unless a modal)\n\twhile (popup_idx > 0)\n\t{\n\t\tImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;\n\t\tImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;\n\t\tbool close_parent = false;\n\t\tif (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))\n\t\t\tif (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar))\n\t\t\t\tclose_parent = true;\n\t\tif (!close_parent)\n\t\t\tbreak;\n\t\tpopup_idx--;\n\t}\n\tIMGUI_DEBUG_LOG_POPUP(\"[popup] CloseCurrentPopup %d -> %d\\n\", g.BeginPopupStack.Size - 1, popup_idx);\n\tClosePopupToLevel(popup_idx, true);\n\n\t// A common pattern is to close a popup when selecting a menu item/selectable that will open another window.\n\t// To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.\n\t// Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.\n\tif (ImGuiWindow* window = g.NavWindow)\n\t\twindow->DC.NavHideHighlightOneFrame = true;\n}\n\n// Attention! BeginPopup() adds default flags which BeginPopupEx()!\nbool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!IsPopupOpen(id, ImGuiPopupFlags_None))\n\t{\n\t\tg.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values\n\t\treturn false;\n\t}\n\n\tchar name[20];\n\tif (flags & ImGuiWindowFlags_ChildMenu)\n\t\tImFormatString(name, IM_ARRAYSIZE(name), \"##Menu_%02d\", g.BeginMenuCount); // Recycle windows based on depth\n\telse\n\t\tImFormatString(name, IM_ARRAYSIZE(name), \"##Popup_%08x\", id); // Not recycling, so we can close/open during the same frame\n\n\tflags |= ImGuiWindowFlags_Popup;\n\tbool is_open = Begin(name, NULL, flags);\n\tif (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)\n\t\tEndPopup();\n\n\treturn is_open;\n}\n\nbool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance\n\t{\n\t\tg.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values\n\t\treturn false;\n\t}\n\tflags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;\n\tImGuiID id = g.CurrentWindow->GetID(str_id);\n\treturn BeginPopupEx(id, flags);\n}\n\n// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.\n// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.\nbool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tconst ImGuiID id = window->GetID(name);\n\tif (!IsPopupOpen(id, ImGuiPopupFlags_None))\n\t{\n\t\tg.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values\n\t\treturn false;\n\t}\n\n\t// Center modal windows by default for increased visibility\n\t// (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)\n\t// FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.\n\tif ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)\n\t{\n\t\tconst ImGuiViewport* viewport = GetMainViewport();\n\t\tSetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));\n\t}\n\n\tflags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse;\n\tconst bool is_open = Begin(name, p_open, flags);\n\tif (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)\n\t{\n\t\tEndPopup();\n\t\tif (is_open)\n\t\t\tClosePopupToLevel(g.BeginPopupStack.Size, true);\n\t\treturn false;\n\t}\n\treturn is_open;\n}\n\nvoid ImGui::EndPopup()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls\n\tIM_ASSERT(g.BeginPopupStack.Size > 0);\n\n\t// Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests)\n\tif (g.NavWindow == window)\n\t\tNavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);\n\n\t// Child-popups don't need to be laid out\n\tIM_ASSERT(g.WithinEndChild == false);\n\tif (window->Flags & ImGuiWindowFlags_ChildWindow)\n\t\tg.WithinEndChild = true;\n\tEnd();\n\tg.WithinEndChild = false;\n}\n\n// Helper to open a popup if mouse button is released over the item\n// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()\nvoid ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tint mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);\n\tif (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))\n\t{\n\t\tImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID;    // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!\n\t\tIM_ASSERT(id != 0);                                             // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)\n\t\tOpenPopupEx(id, popup_flags);\n\t}\n}\n\n// This is a helper to handle the simplest case of associating one named popup to one given widget.\n// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.\n// - To create a popup with a specific identifier, pass it in str_id.\n//    - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.\n//    - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.\n// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).\n//   This is essentially the same as:\n//       id = str_id ? GetID(str_id) : GetItemID();\n//       OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight);\n//       return BeginPopup(id);\n//   Which is essentially the same as:\n//       id = str_id ? GetID(str_id) : GetItemID();\n//       if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))\n//           OpenPopup(id);\n//       return BeginPopup(id);\n//   The main difference being that this is tweaked to avoid computing the ID twice.\nbool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\tImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID;    // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!\n\tIM_ASSERT(id != 0);                                             // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)\n\tint mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);\n\tif (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))\n\t\tOpenPopupEx(id, popup_flags);\n\treturn BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);\n}\n\nbool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (!str_id)\n\t\tstr_id = \"window_context\";\n\tImGuiID id = window->GetID(str_id);\n\tint mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);\n\tif (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))\n\t\tif (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())\n\t\t\tOpenPopupEx(id, popup_flags);\n\treturn BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);\n}\n\nbool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (!str_id)\n\t\tstr_id = \"void_context\";\n\tImGuiID id = window->GetID(str_id);\n\tint mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);\n\tif (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))\n\t\tif (GetTopMostPopupModal() == NULL)\n\t\t\tOpenPopupEx(id, popup_flags);\n\treturn BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);\n}\n\n// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)\n// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.\n// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor\n//  information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.\n//  this allows us to have tooltips/popups displayed out of the parent viewport.)\nImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)\n{\n\tImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);\n\t//GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));\n\t//GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));\n\n\t// Combo Box policy (we want a connecting edge)\n\tif (policy == ImGuiPopupPositionPolicy_ComboBox)\n\t{\n\t\tconst ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };\n\t\tfor (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)\n\t\t{\n\t\t\tconst ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];\n\t\t\tif (n != -1 && dir == *last_dir) // Already tried this direction?\n\t\t\t\tcontinue;\n\t\t\tImVec2 pos;\n\t\t\tif (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)\n\t\t\tif (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right\n\t\t\tif (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left\n\t\t\tif (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left\n\t\t\tif (!r_outer.Contains(ImRect(pos, pos + size)))\n\t\t\t\tcontinue;\n\t\t\t*last_dir = dir;\n\t\t\treturn pos;\n\t\t}\n\t}\n\n\t// Tooltip and Default popup policy\n\t// (Always first try the direction we used on the last frame, if any)\n\tif (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default)\n\t{\n\t\tconst ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };\n\t\tfor (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)\n\t\t{\n\t\t\tconst ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];\n\t\t\tif (n != -1 && dir == *last_dir) // Already tried this direction?\n\t\t\t\tcontinue;\n\n\t\t\tconst float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);\n\t\t\tconst float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);\n\n\t\t\t// If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width)\n\t\t\tif (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))\n\t\t\t\tcontinue;\n\t\t\tif (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))\n\t\t\t\tcontinue;\n\n\t\t\tImVec2 pos;\n\t\t\tpos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;\n\t\t\tpos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;\n\n\t\t\t// Clamp top-left corner of popup\n\t\t\tpos.x = ImMax(pos.x, r_outer.Min.x);\n\t\t\tpos.y = ImMax(pos.y, r_outer.Min.y);\n\n\t\t\t*last_dir = dir;\n\t\t\treturn pos;\n\t\t}\n\t}\n\n\t// Fallback when not enough room:\n\t*last_dir = ImGuiDir_None;\n\n\t// For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.\n\tif (policy == ImGuiPopupPositionPolicy_Tooltip)\n\t\treturn ref_pos + ImVec2(2, 2);\n\n\t// Otherwise try to keep within display\n\tImVec2 pos = ref_pos;\n\tpos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);\n\tpos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);\n\treturn pos;\n}\n\n// Note that this is used for popups, which can overlap the non work-area of individual viewports.\nImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_UNUSED(window);\n\tImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect();\n\tImVec2 padding = g.Style.DisplaySafeAreaPadding;\n\tr_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));\n\treturn r_screen;\n}\n\nImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\n\tImRect r_outer = GetPopupAllowedExtentRect(window);\n\tif (window->Flags & ImGuiWindowFlags_ChildMenu)\n\t{\n\t\t// Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.\n\t\t// This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.\n\t\tIM_ASSERT(g.CurrentWindow == window);\n\t\tImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window;\n\t\tfloat horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).\n\t\tImRect r_avoid;\n\t\tif (parent_window->DC.MenuBarAppending)\n\t\t\tr_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field\n\t\telse\n\t\t\tr_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);\n\t\treturn FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);\n\t}\n\tif (window->Flags & ImGuiWindowFlags_Popup)\n\t{\n\t\treturn FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here\n\t}\n\tif (window->Flags & ImGuiWindowFlags_Tooltip)\n\t{\n\t\t// Position tooltip (always follows mouse + clamp within outer boundaries)\n\t\t// Note that drag and drop tooltips are NOT using this path: BeginTooltipEx() manually sets their position.\n\t\t// In theory we could handle both cases in same location, but requires a bit of shuffling as drag and drop tooltips are calling SetWindowPos() leading to 'window_pos_set_by_api' being set in Begin()\n\t\tIM_ASSERT(g.CurrentWindow == window);\n\t\tconst float scale = g.Style.MouseCursorScale;\n\t\tconst ImVec2 ref_pos = NavCalcPreferredRefPos();\n\t\tconst ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET * scale;\n\t\tImRect r_avoid;\n\t\tif (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))\n\t\t\tr_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);\n\t\telse\n\t\t\tr_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.\n\t\t//GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255));\n\t\treturn FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);\n\t}\n\tIM_ASSERT(0);\n\treturn window->Pos;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] KEYBOARD/GAMEPAD NAVIGATION\n//-----------------------------------------------------------------------------\n\n// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked.\n// In our terminology those should be interchangeable, yet right now this is super confusing.\n// Those two functions are merely a legacy artifact, so at minimum naming should be clarified.\n\nvoid ImGui::SetNavWindow(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.NavWindow != window)\n\t{\n\t\tIMGUI_DEBUG_LOG_FOCUS(\"[focus] SetNavWindow(\\\"%s\\\")\\n\", window ? window->Name : \"<NULL>\");\n\t\tg.NavWindow = window;\n\t}\n\tg.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false;\n\tNavUpdateAnyRequestFlag();\n}\n\nvoid ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX;\n}\n\nvoid ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.NavWindow != NULL);\n\tIM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);\n\tg.NavId = id;\n\tg.NavLayer = nav_layer;\n\tg.NavFocusScopeId = focus_scope_id;\n\tg.NavWindow->NavLastIds[nav_layer] = id;\n\tg.NavWindow->NavRectRel[nav_layer] = rect_rel;\n\n\t// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)\n\tNavClearPreferredPosForAxis(ImGuiAxis_X);\n\tNavClearPreferredPosForAxis(ImGuiAxis_Y);\n}\n\nvoid ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(id != 0);\n\n\tif (g.NavWindow != window)\n\t\tSetNavWindow(window);\n\n\t// Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid.\n\t// Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)\n\tconst ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;\n\tg.NavId = id;\n\tg.NavLayer = nav_layer;\n\tg.NavFocusScopeId = g.CurrentFocusScopeId;\n\twindow->NavLastIds[nav_layer] = id;\n\tif (g.LastItemData.ID == id)\n\t\twindow->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);\n\n\tif (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)\n\t\tg.NavDisableMouseHover = true;\n\telse\n\t\tg.NavDisableHighlight = true;\n\n\t// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)\n\tNavClearPreferredPosForAxis(ImGuiAxis_X);\n\tNavClearPreferredPosForAxis(ImGuiAxis_Y);\n}\n\nstatic ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)\n{\n\tif (ImFabs(dx) > ImFabs(dy))\n\t\treturn (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;\n\treturn (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;\n}\n\nstatic float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max)\n{\n\tif (cand_max < curr_min)\n\t\treturn cand_max - curr_min;\n\tif (curr_max < cand_min)\n\t\treturn cand_min - curr_max;\n\treturn 0.0f;\n}\n\n// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057\nstatic bool ImGui::NavScoreItem(ImGuiNavItemData* result)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (g.NavLayer != window->DC.NavLayerCurrent)\n\t\treturn false;\n\n\t// FIXME: Those are not good variables names\n\tImRect cand = g.LastItemData.NavRect;   // Current item nav rectangle\n\tconst ImRect curr = g.NavScoringRect;   // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)\n\tg.NavScoringDebugCount++;\n\n\t// When entering through a NavFlattened border, we consider child window items as fully clipped for scoring\n\tif (window->ParentWindow == g.NavWindow)\n\t{\n\t\tIM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);\n\t\tif (!window->ClipRect.Overlaps(cand))\n\t\t\treturn false;\n\t\tcand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window\n\t}\n\n\t// Compute distance between boxes\n\t// FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.\n\tfloat dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);\n\tfloat dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items\n\tif (dby != 0.0f && dbx != 0.0f)\n\t\tdbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);\n\tfloat dist_box = ImFabs(dbx) + ImFabs(dby);\n\n\t// Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)\n\tfloat dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);\n\tfloat dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);\n\tfloat dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)\n\n\t// Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance\n\tImGuiDir quadrant;\n\tfloat dax = 0.0f, day = 0.0f, dist_axial = 0.0f;\n\tif (dbx != 0.0f || dby != 0.0f)\n\t{\n\t\t// For non-overlapping boxes, use distance between boxes\n\t\tdax = dbx;\n\t\tday = dby;\n\t\tdist_axial = dist_box;\n\t\tquadrant = ImGetDirQuadrantFromDelta(dbx, dby);\n\t}\n\telse if (dcx != 0.0f || dcy != 0.0f)\n\t{\n\t\t// For overlapping boxes with different centers, use distance between centers\n\t\tdax = dcx;\n\t\tday = dcy;\n\t\tdist_axial = dist_center;\n\t\tquadrant = ImGetDirQuadrantFromDelta(dcx, dcy);\n\t}\n\telse\n\t{\n\t\t// Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)\n\t\tquadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;\n\t}\n\n\tconst ImGuiDir move_dir = g.NavMoveDir;\n#if IMGUI_DEBUG_NAV_SCORING\n\tchar buf[200];\n\tif (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate.\n\t{\n\t\tif (quadrant == move_dir)\n\t\t{\n\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"%.0f/%.0f\", dist_box, dist_center);\n\t\t\tImDrawList* draw_list = GetForegroundDrawList(window);\n\t\t\tdraw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 80));\n\t\t\tdraw_list->AddRectFilled(cand.Min, cand.Min + CalcTextSize(buf), IM_COL32(255, 0, 0, 200));\n\t\t\tdraw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf);\n\t\t}\n\t}\n\tconst bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max);\n\tconst bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space));\n\tif (debug_hovering || debug_tty)\n\t{\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf),\n\t\t\t\"d-box    (%7.3f,%7.3f) -> %7.3f\\nd-center (%7.3f,%7.3f) -> %7.3f\\nd-axial  (%7.3f,%7.3f) -> %7.3f\\nnav %c, quadrant %c\",\n\t\t\tdbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, \"-WENS\"[move_dir + 1], \"-WENS\"[quadrant + 1]);\n\t\tif (debug_hovering)\n\t\t{\n\t\t\tImDrawList* draw_list = GetForegroundDrawList(window);\n\t\t\tdraw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100));\n\t\t\tdraw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200));\n\t\t\tdraw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200));\n\t\t\tdraw_list->AddText(cand.Max, ~0U, buf);\n\t\t}\n\t\tif (debug_tty) { IMGUI_DEBUG_LOG_NAV(\"id 0x%08X\\n%s\\n\", g.LastItemData.ID, buf); }\n\t}\n#endif\n\n\t// Is it in the quadrant we're interested in moving to?\n\tbool new_best = false;\n\tif (quadrant == move_dir)\n\t{\n\t\t// Does it beat the current best candidate?\n\t\tif (dist_box < result->DistBox)\n\t\t{\n\t\t\tresult->DistBox = dist_box;\n\t\t\tresult->DistCenter = dist_center;\n\t\t\treturn true;\n\t\t}\n\t\tif (dist_box == result->DistBox)\n\t\t{\n\t\t\t// Try using distance between center points to break ties\n\t\t\tif (dist_center < result->DistCenter)\n\t\t\t{\n\t\t\t\tresult->DistCenter = dist_center;\n\t\t\t\tnew_best = true;\n\t\t\t}\n\t\t\telse if (dist_center == result->DistCenter)\n\t\t\t{\n\t\t\t\t// Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving \"later\" items\n\t\t\t\t// (with higher index) to the right/downwards by an infinitesimal amount since we the current \"best\" button already (so it must have a lower index),\n\t\t\t\t// this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.\n\t\t\t\tif (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance\n\t\t\t\t\tnew_best = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no \"real\" matches\n\t// are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)\n\t// This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.\n\t// 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.\n\t// Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?\n\tif (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match\n\t\tif (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))\n\t\t\tif ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f))\n\t\t\t{\n\t\t\t\tresult->DistAxial = dist_axial;\n\t\t\t\tnew_best = true;\n\t\t\t}\n\n\treturn new_best;\n}\n\nstatic void ImGui::NavApplyItemToResult(ImGuiNavItemData* result)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tresult->Window = window;\n\tresult->ID = g.LastItemData.ID;\n\tresult->FocusScopeId = g.CurrentFocusScopeId;\n\tresult->InFlags = g.LastItemData.InFlags;\n\tresult->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect);\n}\n\n// True when current work location may be scrolled horizontally when moving left / right.\n// This is generally always true UNLESS within a column. We don't have a vertical equivalent.\nvoid ImGui::NavUpdateCurrentWindowIsScrollPushableX()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\twindow->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL);\n}\n\n// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)\n// This is called after LastItemData is set.\nstatic void ImGui::NavProcessItem()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tconst ImGuiID id = g.LastItemData.ID;\n\tconst ImGuiItemFlags item_flags = g.LastItemData.InFlags;\n\n\t// When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221)\n\tif (window->DC.NavIsScrollPushableX == false)\n\t{\n\t\tg.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x);\n\t\tg.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x);\n\t}\n\tconst ImRect nav_bb = g.LastItemData.NavRect;\n\n\t// Process Init Request\n\tif (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0)\n\t{\n\t\t// Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback\n\t\tconst bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0;\n\t\tif (candidate_for_nav_default_focus || g.NavInitResult.ID == 0)\n\t\t{\n\t\t\tNavApplyItemToResult(&g.NavInitResult);\n\t\t}\n\t\tif (candidate_for_nav_default_focus)\n\t\t{\n\t\t\tg.NavInitRequest = false; // Found a match, clear request\n\t\t\tNavUpdateAnyRequestFlag();\n\t\t}\n\t}\n\n\t// Process Move Request (scoring for navigation)\n\t// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)\n\tif (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0)\n\t{\n\t\tconst bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0;\n\t\tif (is_tabbing)\n\t\t{\n\t\t\tNavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags);\n\t\t}\n\t\telse if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId))\n\t\t{\n\t\t\tImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;\n\t\t\tif (NavScoreItem(result))\n\t\t\t\tNavApplyItemToResult(result);\n\n\t\t\t// Features like PageUp/PageDown need to maintain a separate score for the visible set of items.\n\t\t\tconst float VISIBLE_RATIO = 0.70f;\n\t\t\tif ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))\n\t\t\t\tif (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)\n\t\t\t\t\tif (NavScoreItem(&g.NavMoveResultLocalVisible))\n\t\t\t\t\t\tNavApplyItemToResult(&g.NavMoveResultLocalVisible);\n\t\t}\n\t}\n\n\t// Update information for currently focused/navigated item\n\tif (g.NavId == id)\n\t{\n\t\tif (g.NavWindow != window)\n\t\t\tSetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.\n\t\tg.NavLayer = window->DC.NavLayerCurrent;\n\t\tg.NavFocusScopeId = g.CurrentFocusScopeId;\n\t\tg.NavIdIsAlive = true;\n\t\twindow->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position)\n\t}\n}\n\n// Handle \"scoring\" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest().\n// Note that SetKeyboardFocusHere() API calls are considered tabbing requests!\n// - Case 1: no nav/active id:    set result to first eligible item, stop storing.\n// - Case 2: tab forward:         on ref id set counter, on counter elapse store result\n// - Case 3: tab forward wrap:    set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request\n// - Case 4: tab backward:        store all results, on ref id pick prev, stop storing\n// - Case 5: tab backward wrap:   store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested\nvoid ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\tif ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0)\n\t\tif (g.NavLayer != g.CurrentWindow->DC.NavLayerCurrent)\n\t\t\treturn;\n\n\t// - Can always land on an item when using API call.\n\t// - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item.\n\t// - Tabbing without _NavEnableKeyboard: goes through inputable items only.\n\tbool can_stop;\n\tif (move_flags & ImGuiNavMoveFlags_FocusApi)\n\t\tcan_stop = true;\n\telse\n\t\tcan_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable));\n\n\t// Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows)\n\tImGuiNavItemData* result = &g.NavMoveResultLocal;\n\tif (g.NavTabbingDir == +1)\n\t{\n\t\t// Tab Forward or SetKeyboardFocusHere() with >= 0\n\t\tif (can_stop && g.NavTabbingResultFirst.ID == 0)\n\t\t\tNavApplyItemToResult(&g.NavTabbingResultFirst);\n\t\tif (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0)\n\t\t\tNavMoveRequestResolveWithLastItem(result);\n\t\telse if (g.NavId == id)\n\t\t\tg.NavTabbingCounter = 1;\n\t}\n\telse if (g.NavTabbingDir == -1)\n\t{\n\t\t// Tab Backward\n\t\tif (g.NavId == id)\n\t\t{\n\t\t\tif (result->ID)\n\t\t\t{\n\t\t\t\tg.NavMoveScoringItems = false;\n\t\t\t\tNavUpdateAnyRequestFlag();\n\t\t\t}\n\t\t}\n\t\telse if (can_stop)\n\t\t{\n\t\t\t// Keep applying until reaching NavId\n\t\t\tNavApplyItemToResult(result);\n\t\t}\n\t}\n\telse if (g.NavTabbingDir == 0)\n\t{\n\t\tif (can_stop && g.NavId == id)\n\t\t\tNavMoveRequestResolveWithLastItem(result);\n\t\tif (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init\n\t\t\tNavApplyItemToResult(&g.NavTabbingResultFirst);\n\t}\n}\n\nbool ImGui::NavMoveRequestButNoResultYet()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;\n}\n\n// FIXME: ScoringRect is not set\nvoid ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.NavWindow != NULL);\n\n\tif (move_flags & ImGuiNavMoveFlags_IsTabbing)\n\t\tmove_flags |= ImGuiNavMoveFlags_AllowCurrentNavId;\n\n\tg.NavMoveSubmitted = g.NavMoveScoringItems = true;\n\tg.NavMoveDir = move_dir;\n\tg.NavMoveDirForDebug = move_dir;\n\tg.NavMoveClipDir = clip_dir;\n\tg.NavMoveFlags = move_flags;\n\tg.NavMoveScrollFlags = scroll_flags;\n\tg.NavMoveForwardToNextFrame = false;\n\tg.NavMoveKeyMods = g.IO.KeyMods;\n\tg.NavMoveResultLocal.Clear();\n\tg.NavMoveResultLocalVisible.Clear();\n\tg.NavMoveResultOther.Clear();\n\tg.NavTabbingCounter = 0;\n\tg.NavTabbingResultFirst.Clear();\n\tNavUpdateAnyRequestFlag();\n}\n\nvoid ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavMoveScoringItems = false; // Ensure request doesn't need more processing\n\tNavApplyItemToResult(result);\n\tNavUpdateAnyRequestFlag();\n}\n\n// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere\nvoid ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data)\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavMoveScoringItems = false;\n\tg.LastItemData.ID = tree_node_data->ID;\n\tg.LastItemData.InFlags = tree_node_data->InFlags;\n\tg.LastItemData.NavRect = tree_node_data->NavRect;\n\tNavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult()\n\tNavClearPreferredPosForAxis(ImGuiAxis_Y);\n\tNavUpdateAnyRequestFlag();\n}\n\nvoid ImGui::NavMoveRequestCancel()\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavMoveSubmitted = g.NavMoveScoringItems = false;\n\tNavUpdateAnyRequestFlag();\n}\n\n// Forward will reuse the move request again on the next frame (generally with modifications done to it)\nvoid ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.NavMoveForwardToNextFrame == false);\n\tNavMoveRequestCancel();\n\tg.NavMoveForwardToNextFrame = true;\n\tg.NavMoveDir = move_dir;\n\tg.NavMoveClipDir = clip_dir;\n\tg.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded;\n\tg.NavMoveScrollFlags = scroll_flags;\n}\n\n// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire\n// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.\nvoid ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT((wrap_flags & ImGuiNavMoveFlags_WrapMask_) != 0 && (wrap_flags & ~ImGuiNavMoveFlags_WrapMask_) == 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY\n\n\t// In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it:\n\t// as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest().\n\tif (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main)\n\t\tg.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags;\n}\n\n// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).\n// This way we could find the last focused window among our children. It would be much less confusing this way?\nstatic void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)\n{\n\tImGuiWindow* parent = nav_window;\n\twhile (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)\n\t\tparent = parent->ParentWindow;\n\tif (parent && parent != nav_window)\n\t\tparent->NavLastChildNavWindow = nav_window;\n}\n\n// Restore the last focused child.\n// Call when we are expected to land on the Main Layer (0) after FocusWindow()\nstatic ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)\n{\n\tif (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive)\n\t\treturn window->NavLastChildNavWindow;\n\treturn window;\n}\n\nvoid ImGui::NavRestoreLayer(ImGuiNavLayer layer)\n{\n\tImGuiContext& g = *GImGui;\n\tif (layer == ImGuiNavLayer_Main)\n\t{\n\t\tImGuiWindow* prev_nav_window = g.NavWindow;\n\t\tg.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);    // FIXME-NAV: Should clear ongoing nav requests?\n\t\tif (prev_nav_window)\n\t\t\tIMGUI_DEBUG_LOG_FOCUS(\"[focus] NavRestoreLayer: from \\\"%s\\\" to SetNavWindow(\\\"%s\\\")\\n\", prev_nav_window->Name, g.NavWindow->Name);\n\t}\n\tImGuiWindow* window = g.NavWindow;\n\tif (window->NavLastIds[layer] != 0)\n\t{\n\t\tSetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);\n\t}\n\telse\n\t{\n\t\tg.NavLayer = layer;\n\t\tNavInitWindow(window, true);\n\t}\n}\n\nvoid ImGui::NavRestoreHighlightAfterMove()\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavDisableHighlight = false;\n\tg.NavDisableMouseHover = g.NavMousePosDirty = true;\n}\n\nstatic inline void ImGui::NavUpdateAnyRequestFlag()\n{\n\tImGuiContext& g = *GImGui;\n\tg.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);\n\tif (g.NavAnyRequest)\n\t\tIM_ASSERT(g.NavWindow != NULL);\n}\n\n// This needs to be called before we submit any widget (aka in or before Begin)\nvoid ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(window == g.NavWindow);\n\n\tif (window->Flags & ImGuiWindowFlags_NoNavInputs)\n\t{\n\t\tg.NavId = 0;\n\t\tg.NavFocusScopeId = window->NavRootFocusScopeId;\n\t\treturn;\n\t}\n\n\tbool init_for_nav = false;\n\tif (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)\n\t\tinit_for_nav = true;\n\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\\\"%s\\\", layer=%d\\n\", init_for_nav, window->Name, g.NavLayer);\n\tif (init_for_nav)\n\t{\n\t\tSetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect());\n\t\tg.NavInitRequest = true;\n\t\tg.NavInitRequestFromMove = false;\n\t\tg.NavInitResult.ID = 0;\n\t\tNavUpdateAnyRequestFlag();\n\t}\n\telse\n\t{\n\t\tg.NavId = window->NavLastIds[0];\n\t\tg.NavFocusScopeId = window->NavRootFocusScopeId;\n\t}\n}\n\nstatic ImVec2 ImGui::NavCalcPreferredRefPos()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.NavWindow;\n\tif (g.NavDisableHighlight || !g.NavDisableMouseHover || !window)\n\t{\n\t\t// Mouse (we need a fallback in case the mouse becomes invalid after being used)\n\t\t// The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard.\n\t\t// In theory we could move that +1.0f offset in OpenPopupEx()\n\t\tImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLastValidPos;\n\t\treturn ImVec2(p.x + 1.0f, p.y);\n\t}\n\telse\n\t{\n\t\t// When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item\n\t\t// Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?)\n\t\tImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]);\n\t\tif (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX))\n\t\t{\n\t\t\tImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);\n\t\t\trect_rel.Translate(window->Scroll - next_scroll);\n\t\t}\n\t\tImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight()));\n\t\tImGuiViewport* viewport = GetMainViewport();\n\t\treturn ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta.\n\t}\n}\n\nfloat ImGui::GetNavTweakPressedAmount(ImGuiAxis axis)\n{\n\tImGuiContext& g = *GImGui;\n\tfloat repeat_delay, repeat_rate;\n\tGetTypematicRepeatRate(ImGuiInputFlags_RepeatRateNavTweak, &repeat_delay, &repeat_rate);\n\n\tImGuiKey key_less, key_more;\n\tif (g.NavInputSource == ImGuiInputSource_Gamepad)\n\t{\n\t\tkey_less = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadLeft : ImGuiKey_GamepadDpadUp;\n\t\tkey_more = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadRight : ImGuiKey_GamepadDpadDown;\n\t}\n\telse\n\t{\n\t\tkey_less = (axis == ImGuiAxis_X) ? ImGuiKey_LeftArrow : ImGuiKey_UpArrow;\n\t\tkey_more = (axis == ImGuiAxis_X) ? ImGuiKey_RightArrow : ImGuiKey_DownArrow;\n\t}\n\tfloat amount = (float)GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - (float)GetKeyPressedAmount(key_less, repeat_delay, repeat_rate);\n\tif (amount != 0.0f && IsKeyDown(key_less) && IsKeyDown(key_more)) // Cancel when opposite directions are held, regardless of repeat phase\n\t\tamount = 0.0f;\n\treturn amount;\n}\n\nstatic void ImGui::NavUpdate()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\n\tio.WantSetMousePos = false;\n\t//if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV(\"[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\\n\", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : \"NULL\", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);\n\n\t// Set input source based on which keys are last pressed (as some features differs when used with Gamepad vs Keyboard)\n\t// FIXME-NAV: Now that keys are separated maybe we can get rid of NavInputSource?\n\tconst bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\tconst ImGuiKey nav_gamepad_keys_to_change_source[] = { ImGuiKey_GamepadFaceRight, ImGuiKey_GamepadFaceLeft, ImGuiKey_GamepadFaceUp, ImGuiKey_GamepadFaceDown, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown };\n\tif (nav_gamepad_active)\n\t\tfor (ImGuiKey key : nav_gamepad_keys_to_change_source)\n\t\t\tif (IsKeyDown(key))\n\t\t\t\tg.NavInputSource = ImGuiInputSource_Gamepad;\n\tconst bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;\n\tconst ImGuiKey nav_keyboard_keys_to_change_source[] = { ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, ImGuiKey_RightArrow, ImGuiKey_LeftArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow };\n\tif (nav_keyboard_active)\n\t\tfor (ImGuiKey key : nav_keyboard_keys_to_change_source)\n\t\t\tif (IsKeyDown(key))\n\t\t\t\tg.NavInputSource = ImGuiInputSource_Keyboard;\n\n\t// Process navigation init request (select first/default focus)\n\tg.NavJustMovedToId = 0;\n\tif (g.NavInitResult.ID != 0)\n\t\tNavInitRequestApplyResult();\n\tg.NavInitRequest = false;\n\tg.NavInitRequestFromMove = false;\n\tg.NavInitResult.ID = 0;\n\n\t// Process navigation move request\n\tif (g.NavMoveSubmitted)\n\t\tNavMoveRequestApplyResult();\n\tg.NavTabbingCounter = 0;\n\tg.NavMoveSubmitted = g.NavMoveScoringItems = false;\n\n\t// Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)\n\tbool set_mouse_pos = false;\n\tif (g.NavMousePosDirty && g.NavIdIsAlive)\n\t\tif (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)\n\t\t\tset_mouse_pos = true;\n\tg.NavMousePosDirty = false;\n\tIM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu);\n\n\t// Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0\n\tif (g.NavWindow)\n\t\tNavSaveLastChildNavWindowIntoParent(g.NavWindow);\n\tif (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)\n\t\tg.NavWindow->NavLastChildNavWindow = NULL;\n\n\t// Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)\n\tNavUpdateWindowing();\n\n\t// Set output flags for user application\n\tio.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);\n\tio.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);\n\n\t// Process NavCancel input (to close a popup, get back to parent, clear focus)\n\tNavUpdateCancelRequest();\n\n\t// Process manual activation request\n\tg.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0;\n\tg.NavActivateFlags = ImGuiActivateFlags_None;\n\tif (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))\n\t{\n\t\tconst bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate));\n\t\tconst bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false)));\n\t\tconst bool input_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Enter)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput));\n\t\tconst bool input_pressed = input_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Enter, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, false)));\n\t\tif (g.ActiveId == 0 && activate_pressed)\n\t\t{\n\t\t\tg.NavActivateId = g.NavId;\n\t\t\tg.NavActivateFlags = ImGuiActivateFlags_PreferTweak;\n\t\t}\n\t\tif ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed)\n\t\t{\n\t\t\tg.NavActivateId = g.NavId;\n\t\t\tg.NavActivateFlags = ImGuiActivateFlags_PreferInput;\n\t\t}\n\t\tif ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down))\n\t\t\tg.NavActivateDownId = g.NavId;\n\t\tif ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed))\n\t\t\tg.NavActivatePressedId = g.NavId;\n\t}\n\tif (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))\n\t\tg.NavDisableHighlight = true;\n\tif (g.NavActivateId != 0)\n\t\tIM_ASSERT(g.NavActivateDownId == g.NavActivateId);\n\n\t// Process programmatic activation request\n\t// FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others)\n\tif (g.NavNextActivateId != 0)\n\t{\n\t\tg.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId;\n\t\tg.NavActivateFlags = g.NavNextActivateFlags;\n\t}\n\tg.NavNextActivateId = 0;\n\n\t// Process move requests\n\tNavUpdateCreateMoveRequest();\n\tif (g.NavMoveDir == ImGuiDir_None)\n\t\tNavUpdateCreateTabbingRequest();\n\tNavUpdateAnyRequestFlag();\n\tg.NavIdIsAlive = false;\n\n\t// Scrolling\n\tif (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)\n\t{\n\t\t// *Fallback* manual-scroll with Nav directional keys when window has no navigable item\n\t\tImGuiWindow* window = g.NavWindow;\n\t\tconst float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.\n\t\tconst ImGuiDir move_dir = g.NavMoveDir;\n\t\tif (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None)\n\t\t{\n\t\t\tif (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)\n\t\t\t\tSetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));\n\t\t\tif (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down)\n\t\t\t\tSetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));\n\t\t}\n\n\t\t// *Normal* Manual scroll with LStick\n\t\t// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.\n\t\tif (nav_gamepad_active)\n\t\t{\n\t\t\tconst ImVec2 scroll_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown);\n\t\t\tconst float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f;\n\t\t\tif (scroll_dir.x != 0.0f && window->ScrollbarX)\n\t\t\t\tSetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor));\n\t\t\tif (scroll_dir.y != 0.0f)\n\t\t\t\tSetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed * tweak_factor));\n\t\t}\n\t}\n\n\t// Always prioritize mouse highlight if navigation is disabled\n\tif (!nav_keyboard_active && !nav_gamepad_active)\n\t{\n\t\tg.NavDisableHighlight = true;\n\t\tg.NavDisableMouseHover = set_mouse_pos = false;\n\t}\n\n\t// Update mouse position if requested\n\t// (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied)\n\tif (set_mouse_pos && (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos))\n\t{\n\t\tio.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();\n\t\tio.WantSetMousePos = true;\n\t\t//IMGUI_DEBUG_LOG_IO(\"SetMousePos: (%.1f,%.1f)\\n\", io.MousePos.x, io.MousePos.y);\n\t}\n\n\t// [DEBUG]\n\tg.NavScoringDebugCount = 0;\n#if IMGUI_DEBUG_NAV_RECTS\n\tif (ImGuiWindow* debug_window = g.NavWindow)\n\t{\n\t\tImDrawList* draw_list = GetForegroundDrawList(debug_window);\n\t\tint layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); }\n\t\t//if (1) { ImU32 col = (!debug_window->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, \"%d\", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }\n\t}\n#endif\n}\n\nvoid ImGui::NavInitRequestApplyResult()\n{\n\t// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)\n\tImGuiContext& g = *GImGui;\n\tif (!g.NavWindow)\n\t\treturn;\n\n\tImGuiNavItemData* result = &g.NavInitResult;\n\tif (g.NavId != result->ID)\n\t{\n\t\tg.NavJustMovedToId = result->ID;\n\t\tg.NavJustMovedToFocusScopeId = result->FocusScopeId;\n\t\tg.NavJustMovedToKeyMods = 0;\n\t}\n\n\t// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)\n\t// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.\n\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \\\"%s\\\"\\n\", result->ID, g.NavLayer, g.NavWindow->Name);\n\tSetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);\n\tg.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result\n\tif (g.NavInitRequestFromMove)\n\t\tNavRestoreHighlightAfterMove();\n}\n\n// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position\nstatic void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags)\n{\n\t// Bias initial rect\n\tImGuiContext& g = *GImGui;\n\tconst ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos;\n\n\t// Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias.\n\t// - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column.\n\t// - But each successful move sets new bias on one axis, only cleared when using mouse.\n\tif ((move_flags & ImGuiNavMoveFlags_Forwarded) == 0)\n\t{\n\t\tif (preferred_pos_rel.x == FLT_MAX)\n\t\t\tpreferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x;\n\t\tif (preferred_pos_rel.y == FLT_MAX)\n\t\t\tpreferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y;\n\t}\n\n\t// Apply general bias on the other axis\n\tif ((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) && preferred_pos_rel.x != FLT_MAX)\n\t\tr.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x;\n\telse if ((move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) && preferred_pos_rel.y != FLT_MAX)\n\t\tr.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y;\n}\n\nvoid ImGui::NavUpdateCreateMoveRequest()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\tImGuiWindow* window = g.NavWindow;\n\tconst bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\tconst bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;\n\n\tif (g.NavMoveForwardToNextFrame && window != NULL)\n\t{\n\t\t// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)\n\t\t// (preserve most state, which were already set by the NavMoveRequestForward() function)\n\t\tIM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);\n\t\tIM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded);\n\t\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavMoveRequestForward %d\\n\", g.NavMoveDir);\n\t}\n\telse\n\t{\n\t\t// Initiate directional inputs request\n\t\tg.NavMoveDir = ImGuiDir_None;\n\t\tg.NavMoveFlags = ImGuiNavMoveFlags_None;\n\t\tg.NavMoveScrollFlags = ImGuiScrollFlags_None;\n\t\tif (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))\n\t\t{\n\t\t\tconst ImGuiInputFlags repeat_mode = ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateNavMove;\n\t\t\tif (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Left; }\n\t\t\tif (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Right; }\n\t\t\tif (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Up; }\n\t\t\tif (!IsActiveIdUsingNavDir(ImGuiDir_Down) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadDown, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_DownArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Down; }\n\t\t}\n\t\tg.NavMoveClipDir = g.NavMoveDir;\n\t\tg.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);\n\t}\n\n\t// Update PageUp/PageDown/Home/End scroll\n\t// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?\n\tfloat scoring_rect_offset_y = 0.0f;\n\tif (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)\n\t\tscoring_rect_offset_y = NavUpdatePageUpPageDown();\n\tif (scoring_rect_offset_y != 0.0f)\n\t{\n\t\tg.NavScoringNoClipRect = window->InnerRect;\n\t\tg.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y);\n\t}\n\n\t// [DEBUG] Always send a request when holding CTRL. Hold CTRL + Arrow change the direction.\n#if IMGUI_DEBUG_NAV_SCORING\n\t//if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C))\n\t//    g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3);\n\tif (io.KeyCtrl)\n\t{\n\t\tif (g.NavMoveDir == ImGuiDir_None)\n\t\t\tg.NavMoveDir = g.NavMoveDirForDebug;\n\t\tg.NavMoveClipDir = g.NavMoveDir;\n\t\tg.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult;\n\t}\n#endif\n\n\t// Submit\n\tg.NavMoveForwardToNextFrame = false;\n\tif (g.NavMoveDir != ImGuiDir_None)\n\t\tNavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags);\n\n\t// Moving with no reference triggers an init request (will be used as a fallback if the direction fails to find a match)\n\tif (g.NavMoveSubmitted && g.NavId == 0)\n\t{\n\t\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavInitRequest: from move, window \\\"%s\\\", layer=%d\\n\", window ? window->Name : \"<NULL>\", g.NavLayer);\n\t\tg.NavInitRequest = g.NavInitRequestFromMove = true;\n\t\tg.NavInitResult.ID = 0;\n\t\tg.NavDisableHighlight = false;\n\t}\n\n\t// When using gamepad, we project the reference nav bounding box into window visible area.\n\t// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling,\n\t// since with gamepad all movements are relative (can't focus a visible object like we can with the mouse).\n\tif (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))\n\t{\n\t\tbool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;\n\t\tbool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;\n\t\tImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));\n\n\t\t// Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171)\n\t\t// Otherwise 'inner_rect_rel' would be off on the move result frame.\n\t\tinner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll);\n\n\t\tif ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))\n\t\t{\n\t\t\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavMoveRequest: clamp NavRectRel for gamepad move\\n\");\n\t\t\tfloat pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f);\n\t\t\tfloat pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item\n\t\t\tinner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;\n\t\t\tinner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX;\n\t\t\tinner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;\n\t\t\tinner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX;\n\t\t\twindow->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);\n\t\t\tg.NavId = 0;\n\t\t}\n\t}\n\n\t// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)\n\tImRect scoring_rect;\n\tif (window != NULL)\n\t{\n\t\tImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);\n\t\tscoring_rect = WindowRectRelToAbs(window, nav_rect_rel);\n\t\tscoring_rect.TranslateY(scoring_rect_offset_y);\n\t\tif (g.NavMoveSubmitted)\n\t\t\tNavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags);\n\t\tIM_ASSERT(!scoring_rect.IsInverted()); // Ensure we have a non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().\n\t\t//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]\n\t\t//if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]\n\t}\n\tg.NavScoringRect = scoring_rect;\n\tg.NavScoringNoClipRect.Add(scoring_rect);\n}\n\nvoid ImGui::NavUpdateCreateTabbingRequest()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.NavWindow;\n\tIM_ASSERT(g.NavMoveDir == ImGuiDir_None);\n\tif (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs))\n\t\treturn;\n\n\tconst bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat) && !g.IO.KeyCtrl && !g.IO.KeyAlt;\n\tif (!tab_pressed)\n\t\treturn;\n\n\t// Initiate tabbing request\n\t// (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!)\n\t// Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests.\n\t// See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping.\n\tconst bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;\n\tif (nav_keyboard_active)\n\t\tg.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1;\n\telse\n\t\tg.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1;\n\tImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate;\n\tImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;\n\tImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down;\n\tNavMoveRequestSubmit(ImGuiDir_None, clip_dir, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.\n\tg.NavTabbingCounter = -1;\n}\n\n// Apply result from previous frame navigation directional move request. Always called from NavUpdate()\nvoid ImGui::NavMoveRequestApplyResult()\n{\n\tImGuiContext& g = *GImGui;\n#if IMGUI_DEBUG_NAV_SCORING\n\tif (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times\n\t\treturn;\n#endif\n\n\t// Select which result to use\n\tImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL;\n\n\t// Tabbing forward wrap\n\tif ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && result == NULL)\n\t\tif ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID)\n\t\t\tresult = &g.NavTabbingResultFirst;\n\n\t// In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)\n\tconst ImGuiAxis axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;\n\tif (result == NULL)\n\t{\n\t\tif (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing)\n\t\t\tg.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight;\n\t\tif (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0)\n\t\t\tNavRestoreHighlightAfterMove();\n\t\tNavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis.\n\t\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavMoveSubmitted but not led to a result!\\n\");\n\t\treturn;\n\t}\n\n\t// PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.\n\tif (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)\n\t\tif (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId)\n\t\t\tresult = &g.NavMoveResultLocalVisible;\n\n\t// Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.\n\tif (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)\n\t\tif ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))\n\t\t\tresult = &g.NavMoveResultOther;\n\tIM_ASSERT(g.NavWindow && result->Window);\n\n\t// Scroll to keep newly navigated item fully into view.\n\tif (g.NavLayer == ImGuiNavLayer_Main)\n\t{\n\t\tImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel);\n\t\tScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags);\n\n\t\tif (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY)\n\t\t{\n\t\t\t// FIXME: Should remove this? Or make more precise: use ScrollToRectEx() with edge?\n\t\t\tfloat scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;\n\t\t\tSetScrollY(result->Window, scroll_target);\n\t\t}\n\t}\n\n\tif (g.NavWindow != result->Window)\n\t{\n\t\tIMGUI_DEBUG_LOG_FOCUS(\"[focus] NavMoveRequest: SetNavWindow(\\\"%s\\\")\\n\", result->Window->Name);\n\t\tg.NavWindow = result->Window;\n\t}\n\tif (g.ActiveId != result->ID)\n\t\tClearActiveID();\n\n\t// Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)\n\t// PageUp/PageDown however sets always set NavJustMovedTo (vs Home/End which doesn't) mimicking Windows behavior.\n\tif ((g.NavId != result->ID || (g.NavMoveFlags & ImGuiNavMoveFlags_IsPageMove)) && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSelect) == 0)\n\t{\n\t\tg.NavJustMovedToId = result->ID;\n\t\tg.NavJustMovedToFocusScopeId = result->FocusScopeId;\n\t\tg.NavJustMovedToKeyMods = g.NavMoveKeyMods;\n\t}\n\n\t// Apply new NavID/Focus\n\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \\\"%s\\\"\\n\", result->ID, g.NavLayer, g.NavWindow->Name);\n\tImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer];\n\tSetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);\n\n\t// Restore last preferred position for current axis\n\t// (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..)\n\tif ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) == 0)\n\t{\n\t\tpreferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis];\n\t\tg.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel;\n\t}\n\n\t// Tabbing: Activates Inputable, otherwise only Focus\n\tif ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->InFlags & ImGuiItemFlags_Inputable) == 0)\n\t\tg.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate;\n\n\t// Activate\n\tif (g.NavMoveFlags & ImGuiNavMoveFlags_Activate)\n\t{\n\t\tg.NavNextActivateId = result->ID;\n\t\tg.NavNextActivateFlags = ImGuiActivateFlags_None;\n\t\tg.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight;\n\t\tif (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing)\n\t\t\tg.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState;\n\t}\n\n\t// Enable nav highlight\n\tif ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0)\n\t\tNavRestoreHighlightAfterMove();\n}\n\n// Process NavCancel input (to close a popup, get back to parent, clear focus)\n// FIXME: In order to support e.g. Escape to clear a selection we'll need:\n// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it.\n// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept\nstatic void ImGui::NavUpdateCancelRequest()\n{\n\tImGuiContext& g = *GImGui;\n\tconst bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\tconst bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;\n\tif (!(nav_keyboard_active && IsKeyPressed(ImGuiKey_Escape, ImGuiKeyOwner_None)) && !(nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, ImGuiKeyOwner_None)))\n\t\treturn;\n\n\tIMGUI_DEBUG_LOG_NAV(\"[nav] NavUpdateCancelRequest()\\n\");\n\tif (g.ActiveId != 0)\n\t{\n\t\tClearActiveID();\n\t}\n\telse if (g.NavLayer != ImGuiNavLayer_Main)\n\t{\n\t\t// Leave the \"menu\" layer\n\t\tNavRestoreLayer(ImGuiNavLayer_Main);\n\t\tNavRestoreHighlightAfterMove();\n\t}\n\telse if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)\n\t{\n\t\t// Exit child window\n\t\tImGuiWindow* child_window = g.NavWindow;\n\t\tImGuiWindow* parent_window = g.NavWindow->ParentWindow;\n\t\tIM_ASSERT(child_window->ChildId != 0);\n\t\tImRect child_rect = child_window->Rect();\n\t\tFocusWindow(parent_window);\n\t\tSetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));\n\t\tNavRestoreHighlightAfterMove();\n\t}\n\telse if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))\n\t{\n\t\t// Close open popup/menu\n\t\tClosePopupToLevel(g.OpenPopupStack.Size - 1, true);\n\t}\n\telse\n\t{\n\t\t// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were\n\t\tif (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))\n\t\t\tg.NavWindow->NavLastIds[0] = 0;\n\t\tg.NavId = 0;\n\t}\n}\n\n// Handle PageUp/PageDown/Home/End keys\n// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request\n// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference\n// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?\nstatic float ImGui::NavUpdatePageUpPageDown()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.NavWindow;\n\tif ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL)\n\t\treturn 0.0f;\n\n\tconst bool page_up_held = IsKeyDown(ImGuiKey_PageUp, ImGuiKeyOwner_None);\n\tconst bool page_down_held = IsKeyDown(ImGuiKey_PageDown, ImGuiKeyOwner_None);\n\tconst bool home_pressed = IsKeyPressed(ImGuiKey_Home, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat);\n\tconst bool end_pressed = IsKeyPressed(ImGuiKey_End, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat);\n\tif (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out\n\t\treturn 0.0f;\n\n\tif (g.NavLayer != ImGuiNavLayer_Main)\n\t\tNavRestoreLayer(ImGuiNavLayer_Main);\n\n\tif (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY)\n\t{\n\t\t// Fallback manual-scroll when window has no navigable item\n\t\tif (IsKeyPressed(ImGuiKey_PageUp, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat))\n\t\t\tSetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());\n\t\telse if (IsKeyPressed(ImGuiKey_PageDown, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat))\n\t\t\tSetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());\n\t\telse if (home_pressed)\n\t\t\tSetScrollY(window, 0.0f);\n\t\telse if (end_pressed)\n\t\t\tSetScrollY(window, window->ScrollMax.y);\n\t}\n\telse\n\t{\n\t\tImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];\n\t\tconst float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());\n\t\tfloat nav_scoring_rect_offset_y = 0.0f;\n\t\tif (IsKeyPressed(ImGuiKey_PageUp, true))\n\t\t{\n\t\t\tnav_scoring_rect_offset_y = -page_offset_y;\n\t\t\tg.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)\n\t\t\tg.NavMoveClipDir = ImGuiDir_Up;\n\t\t\tg.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove;\n\t\t}\n\t\telse if (IsKeyPressed(ImGuiKey_PageDown, true))\n\t\t{\n\t\t\tnav_scoring_rect_offset_y = +page_offset_y;\n\t\t\tg.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)\n\t\t\tg.NavMoveClipDir = ImGuiDir_Down;\n\t\t\tg.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove;\n\t\t}\n\t\telse if (home_pressed)\n\t\t{\n\t\t\t// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y\n\t\t\t// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result.\n\t\t\t// Preserve current horizontal position if we have any.\n\t\t\tnav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f;\n\t\t\tif (nav_rect_rel.IsInverted())\n\t\t\t\tnav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;\n\t\t\tg.NavMoveDir = ImGuiDir_Down;\n\t\t\tg.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY;\n\t\t\t// FIXME-NAV: MoveClipDir left to _None, intentional?\n\t\t}\n\t\telse if (end_pressed)\n\t\t{\n\t\t\tnav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y;\n\t\t\tif (nav_rect_rel.IsInverted())\n\t\t\t\tnav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;\n\t\t\tg.NavMoveDir = ImGuiDir_Up;\n\t\t\tg.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY;\n\t\t\t// FIXME-NAV: MoveClipDir left to _None, intentional?\n\t\t}\n\t\treturn nav_scoring_rect_offset_y;\n\t}\n\treturn 0.0f;\n}\n\nstatic void ImGui::NavEndFrame()\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Show CTRL+TAB list window\n\tif (g.NavWindowingTarget != NULL)\n\t\tNavUpdateWindowingOverlay();\n\n\t// Perform wrap-around in menus\n\t// FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly.\n\t// FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.\n\tif (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & ImGuiNavMoveFlags_WrapMask_) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0)\n\t\tNavUpdateCreateWrappingRequest();\n}\n\nstatic void ImGui::NavUpdateCreateWrappingRequest()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.NavWindow;\n\n\tbool do_forward = false;\n\tImRect bb_rel = window->NavRectRel[g.NavLayer];\n\tImGuiDir clip_dir = g.NavMoveDir;\n\n\tconst ImGuiNavMoveFlags move_flags = g.NavMoveFlags;\n\t//const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;\n\tif (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))\n\t{\n\t\tbb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x;\n\t\tif (move_flags & ImGuiNavMoveFlags_WrapX)\n\t\t{\n\t\t\tbb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row\n\t\t\tclip_dir = ImGuiDir_Up;\n\t\t}\n\t\tdo_forward = true;\n\t}\n\tif (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))\n\t{\n\t\tbb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x;\n\t\tif (move_flags & ImGuiNavMoveFlags_WrapX)\n\t\t{\n\t\t\tbb_rel.TranslateY(+bb_rel.GetHeight()); // Next row\n\t\t\tclip_dir = ImGuiDir_Down;\n\t\t}\n\t\tdo_forward = true;\n\t}\n\tif (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))\n\t{\n\t\tbb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y;\n\t\tif (move_flags & ImGuiNavMoveFlags_WrapY)\n\t\t{\n\t\t\tbb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column\n\t\t\tclip_dir = ImGuiDir_Left;\n\t\t}\n\t\tdo_forward = true;\n\t}\n\tif (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))\n\t{\n\t\tbb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y;\n\t\tif (move_flags & ImGuiNavMoveFlags_WrapY)\n\t\t{\n\t\t\tbb_rel.TranslateX(+bb_rel.GetWidth()); // Next column\n\t\t\tclip_dir = ImGuiDir_Right;\n\t\t}\n\t\tdo_forward = true;\n\t}\n\tif (!do_forward)\n\t\treturn;\n\twindow->NavRectRel[g.NavLayer] = bb_rel;\n\tNavClearPreferredPosForAxis(ImGuiAxis_X);\n\tNavClearPreferredPosForAxis(ImGuiAxis_Y);\n\tNavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags);\n}\n\nstatic int ImGui::FindWindowFocusIndex(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_UNUSED(g);\n\tint order = window->FocusOrder;\n\tIM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking)\n\tIM_ASSERT(g.WindowsFocusOrder[order] == window);\n\treturn order;\n}\n\nstatic ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)\n{\n\tImGuiContext& g = *GImGui;\n\tfor (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)\n\t\tif (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))\n\t\t\treturn g.WindowsFocusOrder[i];\n\treturn NULL;\n}\n\nstatic void NavUpdateWindowingHighlightWindow(int focus_change_dir)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.NavWindowingTarget);\n\tif (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)\n\t\treturn;\n\n\tconst int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);\n\tImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);\n\tif (!window_target)\n\t\twindow_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);\n\tif (window_target) // Don't reset windowing target if there's a single window in the list\n\t{\n\t\tg.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;\n\t\tg.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f);\n\t}\n\tg.NavWindowingToggleLayer = false;\n}\n\n// Windowing management mode\n// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)\n// Gamepad:  Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)\nstatic void ImGui::NavUpdateWindowing()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\n\tImGuiWindow* apply_focus_window = NULL;\n\tbool apply_toggle_layer = false;\n\n\tImGuiWindow* modal_window = GetTopMostPopupModal();\n\tbool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows that are inside the Begin-stack of that modal.\n\tif (!allow_windowing)\n\t\tg.NavWindowingTarget = NULL;\n\n\t// Fade out\n\tif (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)\n\t{\n\t\tg.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f);\n\t\tif (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)\n\t\t\tg.NavWindowingTargetAnim = NULL;\n\t}\n\n\t// Start CTRL+Tab or Square+L/R window selection\n\tconst ImGuiID owner_id = ImHashStr(\"###NavUpdateWindowing\");\n\tconst bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\tconst bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;\n\tconst bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);\n\tconst bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);\n\tconst bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None);\n\tconst bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard!\n\tif (start_windowing_with_gamepad || start_windowing_with_keyboard)\n\t\tif (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))\n\t\t{\n\t\t\tg.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow;\n\t\t\tg.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;\n\t\t\tg.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f);\n\t\t\tg.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer\n\t\t\tg.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;\n\n\t\t\t// Register ownership of our mods. Using ImGuiInputFlags_RouteGlobalHigh in the Shortcut() calls instead would probably be correct but may have more side-effects.\n\t\t\tif (keyboard_next_window || keyboard_prev_window)\n\t\t\t\tSetKeyOwnersForKeyChord((g.ConfigNavWindowingKeyNext | g.ConfigNavWindowingKeyPrev) & ImGuiMod_Mask_, owner_id);\n\t\t}\n\n\t// Gamepad update\n\tg.NavWindowingTimer += io.DeltaTime;\n\tif (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad)\n\t{\n\t\t// Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise\n\t\tg.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));\n\n\t\t// Select window to focus\n\t\tconst int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1);\n\t\tif (focus_change_dir != 0)\n\t\t{\n\t\t\tNavUpdateWindowingHighlightWindow(focus_change_dir);\n\t\t\tg.NavWindowingHighlightAlpha = 1.0f;\n\t\t}\n\n\t\t// Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)\n\t\tif (!IsKeyDown(ImGuiKey_NavGamepadMenu))\n\t\t{\n\t\t\tg.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.\n\t\t\tif (g.NavWindowingToggleLayer && g.NavWindow)\n\t\t\t\tapply_toggle_layer = true;\n\t\t\telse if (!g.NavWindowingToggleLayer)\n\t\t\t\tapply_focus_window = g.NavWindowingTarget;\n\t\t\tg.NavWindowingTarget = NULL;\n\t\t}\n\t}\n\n\t// Keyboard: Focus\n\tif (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard)\n\t{\n\t\t// Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise\n\t\tImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_;\n\t\tIM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to \"hold\", otherwise Prev actions would keep cycling between two windows.\n\t\tg.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f\n\t\tif (keyboard_next_window || keyboard_prev_window)\n\t\t\tNavUpdateWindowingHighlightWindow(keyboard_next_window ? -1 : +1);\n\t\telse if ((io.KeyMods & shared_mods) != shared_mods)\n\t\t\tapply_focus_window = g.NavWindowingTarget;\n\t}\n\n\t// Keyboard: Press and Release ALT to toggle menu layer\n\t// - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer.\n\t// - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.\n\tif (nav_keyboard_active && IsKeyPressed(ImGuiMod_Alt, ImGuiKeyOwner_None))\n\t{\n\t\tg.NavWindowingToggleLayer = true;\n\t\tg.NavInputSource = ImGuiInputSource_Keyboard;\n\t}\n\tif (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard)\n\t{\n\t\t// We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370)\n\t\t// We cancel toggling nav layer when other modifiers are pressed. (See #4439)\n\t\t// We cancel toggling nav layer if an owner has claimed the key.\n\t\tif (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_None) == false)\n\t\t\tg.NavWindowingToggleLayer = false;\n\n\t\t// Apply layer toggle on release\n\t\t// Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss.\n\t\tif (IsKeyReleased(ImGuiMod_Alt) && g.NavWindowingToggleLayer)\n\t\t\tif (g.ActiveId == 0 || g.ActiveIdAllowOverlap)\n\t\t\t\tif (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev))\n\t\t\t\t\tapply_toggle_layer = true;\n\t\tif (!IsKeyDown(ImGuiMod_Alt))\n\t\t\tg.NavWindowingToggleLayer = false;\n\t}\n\n\t// Move window\n\tif (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))\n\t{\n\t\tImVec2 nav_move_dir;\n\t\tif (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift)\n\t\t\tnav_move_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow);\n\t\tif (g.NavInputSource == ImGuiInputSource_Gamepad)\n\t\t\tnav_move_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown);\n\t\tif (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f)\n\t\t{\n\t\t\tconst float NAV_MOVE_SPEED = 800.0f;\n\t\t\tconst float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);\n\t\t\tg.NavWindowingAccumDeltaPos += nav_move_dir * move_step;\n\t\t\tg.NavDisableMouseHover = true;\n\t\t\tImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaPos);\n\t\t\tif (accum_floored.x != 0.0f || accum_floored.y != 0.0f)\n\t\t\t{\n\t\t\t\tImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;\n\t\t\t\tSetWindowPos(moving_window, moving_window->Pos + accum_floored, ImGuiCond_Always);\n\t\t\t\tg.NavWindowingAccumDeltaPos -= accum_floored;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply final focus\n\tif (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))\n\t{\n\t\tClearActiveID();\n\t\tNavRestoreHighlightAfterMove();\n\t\tClosePopupsOverWindow(apply_focus_window, false);\n\t\tFocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild);\n\t\tapply_focus_window = g.NavWindow;\n\t\tif (apply_focus_window->NavLastIds[0] == 0)\n\t\t\tNavInitWindow(apply_focus_window, false);\n\n\t\t// If the window has ONLY a menu layer (no main layer), select it directly\n\t\t// Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,\n\t\t// so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since\n\t\t// the target window as already been previewed once.\n\t\t// FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,\n\t\t// we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*\n\t\t// won't be valid.\n\t\tif (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))\n\t\t\tg.NavLayer = ImGuiNavLayer_Menu;\n\t}\n\tif (apply_focus_window)\n\t\tg.NavWindowingTarget = NULL;\n\n\t// Apply menu/layer toggle\n\tif (apply_toggle_layer && g.NavWindow)\n\t{\n\t\tClearActiveID();\n\n\t\t// Move to parent menu if necessary\n\t\tImGuiWindow* new_nav_window = g.NavWindow;\n\t\twhile (new_nav_window->ParentWindow\n\t\t\t&& (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0\n\t\t\t&& (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0\n\t\t\t&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)\n\t\t\tnew_nav_window = new_nav_window->ParentWindow;\n\t\tif (new_nav_window != g.NavWindow)\n\t\t{\n\t\t\tImGuiWindow* old_nav_window = g.NavWindow;\n\t\t\tFocusWindow(new_nav_window);\n\t\t\tnew_nav_window->NavLastChildNavWindow = old_nav_window;\n\t\t}\n\n\t\t// Toggle layer\n\t\tconst ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;\n\t\tif (new_nav_layer != g.NavLayer)\n\t\t{\n\t\t\t// Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?)\n\t\t\tif (new_nav_layer == ImGuiNavLayer_Menu)\n\t\t\t\tg.NavWindow->NavLastIds[new_nav_layer] = 0;\n\t\t\tNavRestoreLayer(new_nav_layer);\n\t\t\tNavRestoreHighlightAfterMove();\n\t\t}\n\t}\n}\n\n// Window has already passed the IsWindowNavFocusable()\nstatic const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)\n{\n\tif (window->Flags & ImGuiWindowFlags_Popup)\n\t\treturn ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingPopup);\n\tif ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, \"##MainMenuBar\") == 0)\n\t\treturn ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingMainMenuBar);\n\treturn ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingUntitled);\n}\n\n// Overlay displayed when using CTRL+TAB. Called by EndFrame().\nvoid ImGui::NavUpdateWindowingOverlay()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.NavWindowingTarget != NULL);\n\n\tif (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)\n\t\treturn;\n\n\tif (g.NavWindowingListWindow == NULL)\n\t\tg.NavWindowingListWindow = FindWindowByName(\"###NavWindowingList\");\n\tconst ImGuiViewport* viewport = GetMainViewport();\n\tSetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));\n\tSetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));\n\tPushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);\n\tBegin(\"###NavWindowingList\", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);\n\tfor (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)\n\t{\n\t\tImGuiWindow* window = g.WindowsFocusOrder[n];\n\t\tIM_ASSERT(window != NULL); // Fix static analyzers\n\t\tif (!IsWindowNavFocusable(window))\n\t\t\tcontinue;\n\t\tconst char* label = window->Name;\n\t\tif (label == FindRenderedTextEnd(label))\n\t\t\tlabel = GetFallbackWindowNameForWindowingList(window);\n\t\tSelectable(label, g.NavWindowingTarget == window);\n\t}\n\tEnd();\n\tPopStyleVar();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] DRAG AND DROP\n//-----------------------------------------------------------------------------\n\nbool ImGui::IsDragDropActive()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.DragDropActive;\n}\n\nvoid ImGui::ClearDragDrop()\n{\n\tImGuiContext& g = *GImGui;\n\tg.DragDropActive = false;\n\tg.DragDropPayload.Clear();\n\tg.DragDropAcceptFlags = ImGuiDragDropFlags_None;\n\tg.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;\n\tg.DragDropAcceptIdCurrRectSurface = FLT_MAX;\n\tg.DragDropAcceptFrameCount = -1;\n\n\tg.DragDropPayloadBufHeap.clear();\n\tmemset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));\n}\n\n// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()\n// If the item has an identifier:\n// - This assume/require the item to be activated (typically via ButtonBehavior).\n// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button.\n// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag.\n// If the item has no identifier:\n// - Currently always assume left mouse button.\nbool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// FIXME-DRAGDROP: While in the common-most \"drag from non-zero active id\" case we can tell the mouse button,\n\t// in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic).\n\tImGuiMouseButton mouse_button = ImGuiMouseButton_Left;\n\n\tbool source_drag_active = false;\n\tImGuiID source_id = 0;\n\tImGuiID source_parent_id = 0;\n\tif (!(flags & ImGuiDragDropFlags_SourceExtern))\n\t{\n\t\tsource_id = g.LastItemData.ID;\n\t\tif (source_id != 0)\n\t\t{\n\t\t\t// Common path: items with ID\n\t\t\tif (g.ActiveId != source_id)\n\t\t\t\treturn false;\n\t\t\tif (g.ActiveIdMouseButton != -1)\n\t\t\t\tmouse_button = g.ActiveIdMouseButton;\n\t\t\tif (g.IO.MouseDown[mouse_button] == false || window->SkipItems)\n\t\t\t\treturn false;\n\t\t\tg.ActiveIdAllowOverlap = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Uncommon path: items without ID\n\t\t\tif (g.IO.MouseDown[mouse_button] == false || window->SkipItems)\n\t\t\t\treturn false;\n\t\t\tif ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))\n\t\t\t\treturn false;\n\n\t\t\t// If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:\n\t\t\t// A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag.\n\t\t\tif (!(flags & ImGuiDragDropFlags_SourceAllowNullID))\n\t\t\t{\n\t\t\t\tIM_ASSERT(0);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Magic fallback to handle items with no assigned ID, e.g. Text(), Image()\n\t\t\t// We build a throwaway ID based on current ID stack + relative AABB of items in window.\n\t\t\t// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled.\n\t\t\t// We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.\n\t\t\t// Rely on keeping other window->LastItemXXX fields intact.\n\t\t\tsource_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);\n\t\t\tKeepAliveID(source_id);\n\t\t\tbool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags);\n\t\t\tif (is_hovered && g.IO.MouseClicked[mouse_button])\n\t\t\t{\n\t\t\t\tSetActiveID(source_id, window);\n\t\t\t\tFocusWindow(window);\n\t\t\t}\n\t\t\tif (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.\n\t\t\t\tg.ActiveIdAllowOverlap = is_hovered;\n\t\t}\n\t\tif (g.ActiveId != source_id)\n\t\t\treturn false;\n\t\tsource_parent_id = window->IDStack.back();\n\t\tsource_drag_active = IsMouseDragging(mouse_button);\n\n\t\t// Disable navigation and key inputs while dragging + cancel existing request if any\n\t\tSetActiveIdUsingAllKeyboardKeys();\n\t}\n\telse\n\t{\n\t\twindow = NULL;\n\t\tsource_id = ImHashStr(\"#SourceExtern\");\n\t\tsource_drag_active = true;\n\t}\n\n\tif (source_drag_active)\n\t{\n\t\tif (!g.DragDropActive)\n\t\t{\n\t\t\tIM_ASSERT(source_id != 0);\n\t\t\tClearDragDrop();\n\t\t\tImGuiPayload& payload = g.DragDropPayload;\n\t\t\tpayload.SourceId = source_id;\n\t\t\tpayload.SourceParentId = source_parent_id;\n\t\t\tg.DragDropActive = true;\n\t\t\tg.DragDropSourceFlags = flags;\n\t\t\tg.DragDropMouseButton = mouse_button;\n\t\t\tif (payload.SourceId == g.ActiveId)\n\t\t\t\tg.ActiveIdNoClearOnFocusLoss = true;\n\t\t}\n\t\tg.DragDropSourceFrameCount = g.FrameCount;\n\t\tg.DragDropWithinSource = true;\n\n\t\tif (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))\n\t\t{\n\t\t\t// Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)\n\t\t\t// We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.\n\t\t\tbool ret = BeginTooltip();\n\t\t\tIM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin(\"##Hidden\", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().\n\t\t\tIM_UNUSED(ret);\n\n\t\t\tif (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))\n\t\t\t\tSetWindowHiddendAndSkipItemsForCurrentFrame(g.CurrentWindow);\n\t\t}\n\n\t\tif (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))\n\t\t\tg.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;\n\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid ImGui::EndDragDropSource()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.DragDropActive);\n\tIM_ASSERT(g.DragDropWithinSource && \"Not after a BeginDragDropSource()?\");\n\n\tif (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))\n\t\tEndTooltip();\n\n\t// Discard the drag if have not called SetDragDropPayload()\n\tif (g.DragDropPayload.DataFrameCount == -1)\n\t\tClearDragDrop();\n\tg.DragDropWithinSource = false;\n}\n\n// Use 'cond' to choose to submit payload on drag start or every frame\nbool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiPayload& payload = g.DragDropPayload;\n\tif (cond == 0)\n\t\tcond = ImGuiCond_Always;\n\n\tIM_ASSERT(type != NULL);\n\tIM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && \"Payload type can be at most 32 characters long\");\n\tIM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));\n\tIM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);\n\tIM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()\n\n\tif (cond == ImGuiCond_Always || payload.DataFrameCount == -1)\n\t{\n\t\t// Copy payload\n\t\tImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));\n\t\tg.DragDropPayloadBufHeap.resize(0);\n\t\tif (data_size > sizeof(g.DragDropPayloadBufLocal))\n\t\t{\n\t\t\t// Store in heap\n\t\t\tg.DragDropPayloadBufHeap.resize((int)data_size);\n\t\t\tpayload.Data = g.DragDropPayloadBufHeap.Data;\n\t\t\tmemcpy(payload.Data, data, data_size);\n\t\t}\n\t\telse if (data_size > 0)\n\t\t{\n\t\t\t// Store locally\n\t\t\tmemset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));\n\t\t\tpayload.Data = g.DragDropPayloadBufLocal;\n\t\t\tmemcpy(payload.Data, data, data_size);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpayload.Data = NULL;\n\t\t}\n\t\tpayload.DataSize = (int)data_size;\n\t}\n\tpayload.DataFrameCount = g.FrameCount;\n\n\t// Return whether the payload has been accepted\n\treturn (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);\n}\n\nbool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!g.DragDropActive)\n\t\treturn false;\n\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;\n\tif (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)\n\t\treturn false;\n\tIM_ASSERT(id != 0);\n\tif (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))\n\t\treturn false;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tIM_ASSERT(g.DragDropWithinTarget == false);\n\tg.DragDropTargetRect = bb;\n\tg.DragDropTargetId = id;\n\tg.DragDropWithinTarget = true;\n\treturn true;\n}\n\n// We don't use BeginDragDropTargetCustom() and duplicate its code because:\n// 1) we use LastItemRectHoveredRect which handles items that push a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.\n// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.\n// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)\nbool ImGui::BeginDragDropTarget()\n{\n\tImGuiContext& g = *GImGui;\n\tif (!g.DragDropActive)\n\t\treturn false;\n\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect))\n\t\treturn false;\n\tImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;\n\tif (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow || window->SkipItems)\n\t\treturn false;\n\n\tconst ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;\n\tImGuiID id = g.LastItemData.ID;\n\tif (id == 0)\n\t{\n\t\tid = window->GetIDFromRectangle(display_rect);\n\t\tKeepAliveID(id);\n\t}\n\tif (g.DragDropPayload.SourceId == id)\n\t\treturn false;\n\n\tIM_ASSERT(g.DragDropWithinTarget == false);\n\tg.DragDropTargetRect = display_rect;\n\tg.DragDropTargetId = id;\n\tg.DragDropWithinTarget = true;\n\treturn true;\n}\n\nbool ImGui::IsDragDropPayloadBeingAccepted()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.DragDropActive && g.DragDropAcceptIdPrev != 0;\n}\n\nconst ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiPayload& payload = g.DragDropPayload;\n\tIM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?\n\tIM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?\n\tif (type != NULL && !payload.IsDataType(type))\n\t\treturn NULL;\n\n\t// Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.\n\t// NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!\n\tconst bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);\n\tImRect r = g.DragDropTargetRect;\n\tfloat r_surface = r.GetWidth() * r.GetHeight();\n\tif (r_surface > g.DragDropAcceptIdCurrRectSurface)\n\t\treturn NULL;\n\n\tg.DragDropAcceptFlags = flags;\n\tg.DragDropAcceptIdCurr = g.DragDropTargetId;\n\tg.DragDropAcceptIdCurrRectSurface = r_surface;\n\t//IMGUI_DEBUG_LOG(\"AcceptDragDropPayload(): %08X: accept\\n\", g.DragDropTargetId);\n\n\t// Render default drop visuals\n\tpayload.Preview = was_accepted_previously;\n\tflags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame)\n\tif (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)\n\t\twindow->DrawList->AddRect(r.Min - ImVec2(3.5f, 3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);\n\n\tg.DragDropAcceptFrameCount = g.FrameCount;\n\tpayload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()\n\tif (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))\n\t\treturn NULL;\n\n\t//IMGUI_DEBUG_LOG(\"AcceptDragDropPayload(): %08X: return payload\\n\", g.DragDropTargetId);\n\treturn &payload;\n}\n\n// FIXME-DRAGDROP: Settle on a proper default visuals for drop target.\nvoid ImGui::RenderDragDropTargetRect(const ImRect& bb)\n{\n\tGetWindowDrawList()->AddRect(bb.Min - ImVec2(3.5f, 3.5f), bb.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);\n}\n\nconst ImGuiPayload* ImGui::GetDragDropPayload()\n{\n\tImGuiContext& g = *GImGui;\n\treturn (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL;\n}\n\nvoid ImGui::EndDragDropTarget()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.DragDropActive);\n\tIM_ASSERT(g.DragDropWithinTarget);\n\tg.DragDropWithinTarget = false;\n\n\t// Clear drag and drop state payload right after delivery\n\tif (g.DragDropPayload.Delivery)\n\t\tClearDragDrop();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] LOGGING/CAPTURING\n//-----------------------------------------------------------------------------\n// All text output from the interface can be captured into tty/file/clipboard.\n// By default, tree nodes are automatically opened during logging.\n//-----------------------------------------------------------------------------\n\n// Pass text data straight to log (without being displayed)\nstatic inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args)\n{\n\tif (g.LogFile)\n\t{\n\t\tg.LogBuffer.Buf.resize(0);\n\t\tg.LogBuffer.appendfv(fmt, args);\n\t\tImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);\n\t}\n\telse\n\t{\n\t\tg.LogBuffer.appendfv(fmt, args);\n\t}\n}\n\nvoid ImGui::LogText(const char* fmt, ...)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!g.LogEnabled)\n\t\treturn;\n\n\tva_list args;\n\tva_start(args, fmt);\n\tLogTextV(g, fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::LogTextV(const char* fmt, va_list args)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!g.LogEnabled)\n\t\treturn;\n\n\tLogTextV(g, fmt, args);\n}\n\n// Internal version that takes a position to decide on newline placement and pad items according to their depth.\n// We split text into individual lines to add current tree level padding\n// FIXME: This code is a little complicated perhaps, considering simplifying the whole system.\nvoid ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tconst char* prefix = g.LogNextPrefix;\n\tconst char* suffix = g.LogNextSuffix;\n\tg.LogNextPrefix = g.LogNextSuffix = NULL;\n\n\tif (!text_end)\n\t\ttext_end = FindRenderedTextEnd(text, text_end);\n\n\tconst bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);\n\tif (ref_pos)\n\t\tg.LogLinePosY = ref_pos->y;\n\tif (log_new_line)\n\t{\n\t\tLogText(IM_NEWLINE);\n\t\tg.LogLineFirstItem = true;\n\t}\n\n\tif (prefix)\n\t\tLogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure \"##\" are included here.\n\n\t// Re-adjust padding if we have popped out of our starting depth\n\tif (g.LogDepthRef > window->DC.TreeDepth)\n\t\tg.LogDepthRef = window->DC.TreeDepth;\n\tconst int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);\n\n\tconst char* text_remaining = text;\n\tfor (;;)\n\t{\n\t\t// Split the string. Each new line (after a '\\n') is followed by indentation corresponding to the current depth of our log entry.\n\t\t// We don't add a trailing \\n yet to allow a subsequent item on the same line to be captured.\n\t\tconst char* line_start = text_remaining;\n\t\tconst char* line_end = ImStreolRange(line_start, text_end);\n\t\tconst bool is_last_line = (line_end == text_end);\n\t\tif (line_start != line_end || !is_last_line)\n\t\t{\n\t\t\tconst int line_length = (int)(line_end - line_start);\n\t\t\tconst int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1;\n\t\t\tLogText(\"%*s%.*s\", indentation, \"\", line_length, line_start);\n\t\t\tg.LogLineFirstItem = false;\n\t\t\tif (*line_end == '\\n')\n\t\t\t{\n\t\t\t\tLogText(IM_NEWLINE);\n\t\t\t\tg.LogLineFirstItem = true;\n\t\t\t}\n\t\t}\n\t\tif (is_last_line)\n\t\t\tbreak;\n\t\ttext_remaining = line_end + 1;\n\t}\n\n\tif (suffix)\n\t\tLogRenderedText(ref_pos, suffix, suffix + strlen(suffix));\n}\n\n// Start logging/capturing text output\nvoid ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(g.LogEnabled == false);\n\tIM_ASSERT(g.LogFile == NULL);\n\tIM_ASSERT(g.LogBuffer.empty());\n\tg.LogEnabled = true;\n\tg.LogType = type;\n\tg.LogNextPrefix = g.LogNextSuffix = NULL;\n\tg.LogDepthRef = window->DC.TreeDepth;\n\tg.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);\n\tg.LogLinePosY = FLT_MAX;\n\tg.LogLineFirstItem = true;\n}\n\n// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText)\nvoid ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix)\n{\n\tImGuiContext& g = *GImGui;\n\tg.LogNextPrefix = prefix;\n\tg.LogNextSuffix = suffix;\n}\n\nvoid ImGui::LogToTTY(int auto_open_depth)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.LogEnabled)\n\t\treturn;\n\tIM_UNUSED(auto_open_depth);\n#ifndef IMGUI_DISABLE_TTY_FUNCTIONS\n\tLogBegin(ImGuiLogType_TTY, auto_open_depth);\n\tg.LogFile = stdout;\n#endif\n}\n\n// Start logging/capturing text output to given file\nvoid ImGui::LogToFile(int auto_open_depth, const char* filename)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.LogEnabled)\n\t\treturn;\n\n\t// FIXME: We could probably open the file in text mode \"at\", however note that clipboard/buffer logging will still\n\t// be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.\n\t// By opening the file in binary mode \"ab\" we have consistent output everywhere.\n\tif (!filename)\n\t\tfilename = g.IO.LogFilename;\n\tif (!filename || !filename[0])\n\t\treturn;\n\tImFileHandle f = ImFileOpen(filename, \"ab\");\n\tif (!f)\n\t{\n\t\tIM_ASSERT(0);\n\t\treturn;\n\t}\n\n\tLogBegin(ImGuiLogType_File, auto_open_depth);\n\tg.LogFile = f;\n}\n\n// Start logging/capturing text output to clipboard\nvoid ImGui::LogToClipboard(int auto_open_depth)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.LogEnabled)\n\t\treturn;\n\tLogBegin(ImGuiLogType_Clipboard, auto_open_depth);\n}\n\nvoid ImGui::LogToBuffer(int auto_open_depth)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.LogEnabled)\n\t\treturn;\n\tLogBegin(ImGuiLogType_Buffer, auto_open_depth);\n}\n\nvoid ImGui::LogFinish()\n{\n\tImGuiContext& g = *GImGui;\n\tif (!g.LogEnabled)\n\t\treturn;\n\n\tLogText(IM_NEWLINE);\n\tswitch (g.LogType)\n\t{\n\tcase ImGuiLogType_TTY:\n#ifndef IMGUI_DISABLE_TTY_FUNCTIONS\n\t\tfflush(g.LogFile);\n#endif\n\t\tbreak;\n\tcase ImGuiLogType_File:\n\t\tImFileClose(g.LogFile);\n\t\tbreak;\n\tcase ImGuiLogType_Buffer:\n\t\tbreak;\n\tcase ImGuiLogType_Clipboard:\n\t\tif (!g.LogBuffer.empty())\n\t\t\tSetClipboardText(g.LogBuffer.begin());\n\t\tbreak;\n\tcase ImGuiLogType_None:\n\t\tIM_ASSERT(0);\n\t\tbreak;\n\t}\n\n\tg.LogEnabled = false;\n\tg.LogType = ImGuiLogType_None;\n\tg.LogFile = NULL;\n\tg.LogBuffer.clear();\n}\n\n// Helper to display logging buttons\n// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)\nvoid ImGui::LogButtons()\n{\n\tImGuiContext& g = *GImGui;\n\n\tPushID(\"LogButtons\");\n#ifndef IMGUI_DISABLE_TTY_FUNCTIONS\n\tconst bool log_to_tty = Button(\"Log To TTY\"); SameLine();\n#else\n\tconst bool log_to_tty = false;\n#endif\n\tconst bool log_to_file = Button(\"Log To File\"); SameLine();\n\tconst bool log_to_clipboard = Button(\"Log To Clipboard\"); SameLine();\n\tPushTabStop(false);\n\tSetNextItemWidth(80.0f);\n\tSliderInt(\"Default Depth\", &g.LogDepthToExpandDefault, 0, 9, NULL);\n\tPopTabStop();\n\tPopID();\n\n\t// Start logging at the end of the function so that the buttons don't appear in the log\n\tif (log_to_tty)\n\t\tLogToTTY();\n\tif (log_to_file)\n\t\tLogToFile();\n\tif (log_to_clipboard)\n\t\tLogToClipboard();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] SETTINGS\n//-----------------------------------------------------------------------------\n// - UpdateSettings() [Internal]\n// - MarkIniSettingsDirty() [Internal]\n// - FindSettingsHandler() [Internal]\n// - ClearIniSettings() [Internal]\n// - LoadIniSettingsFromDisk()\n// - LoadIniSettingsFromMemory()\n// - SaveIniSettingsToDisk()\n// - SaveIniSettingsToMemory()\n//-----------------------------------------------------------------------------\n// - CreateNewWindowSettings() [Internal]\n// - FindWindowSettingsByID() [Internal]\n// - FindWindowSettingsByWindow() [Internal]\n// - ClearWindowSettings() [Internal]\n// - WindowSettingsHandler_***() [Internal]\n//-----------------------------------------------------------------------------\n\n// Called by NewFrame()\nvoid ImGui::UpdateSettings()\n{\n\t// Load settings on first frame (if not explicitly loaded manually before)\n\tImGuiContext& g = *GImGui;\n\tif (!g.SettingsLoaded)\n\t{\n\t\tIM_ASSERT(g.SettingsWindows.empty());\n\t\tif (g.IO.IniFilename)\n\t\t\tLoadIniSettingsFromDisk(g.IO.IniFilename);\n\t\tg.SettingsLoaded = true;\n\t}\n\n\t// Save settings (with a delay after the last modification, so we don't spam disk too much)\n\tif (g.SettingsDirtyTimer > 0.0f)\n\t{\n\t\tg.SettingsDirtyTimer -= g.IO.DeltaTime;\n\t\tif (g.SettingsDirtyTimer <= 0.0f)\n\t\t{\n\t\t\tif (g.IO.IniFilename != NULL)\n\t\t\t\tSaveIniSettingsToDisk(g.IO.IniFilename);\n\t\t\telse\n\t\t\t\tg.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.\n\t\t\tg.SettingsDirtyTimer = 0.0f;\n\t\t}\n\t}\n}\n\nvoid ImGui::MarkIniSettingsDirty()\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.SettingsDirtyTimer <= 0.0f)\n\t\tg.SettingsDirtyTimer = g.IO.IniSavingRate;\n}\n\nvoid ImGui::MarkIniSettingsDirty(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))\n\t\tif (g.SettingsDirtyTimer <= 0.0f)\n\t\t\tg.SettingsDirtyTimer = g.IO.IniSavingRate;\n}\n\nvoid ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL);\n\tg.SettingsHandlers.push_back(*handler);\n}\n\nvoid ImGui::RemoveSettingsHandler(const char* type_name)\n{\n\tImGuiContext& g = *GImGui;\n\tif (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name))\n\t\tg.SettingsHandlers.erase(handler);\n}\n\nImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiID type_hash = ImHashStr(type_name);\n\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\tif (handler.TypeHash == type_hash)\n\t\t\treturn &handler;\n\treturn NULL;\n}\n\n// Clear all settings (windows, tables, docking etc.)\nvoid ImGui::ClearIniSettings()\n{\n\tImGuiContext& g = *GImGui;\n\tg.SettingsIniData.clear();\n\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\tif (handler.ClearAllFn != NULL)\n\t\t\thandler.ClearAllFn(&g, &handler);\n}\n\nvoid ImGui::LoadIniSettingsFromDisk(const char* ini_filename)\n{\n\tsize_t file_data_size = 0;\n\tchar* file_data = (char*)ImFileLoadToMemory(ini_filename, \"rb\", &file_data_size);\n\tif (!file_data)\n\t\treturn;\n\tif (file_data_size > 0)\n\t\tLoadIniSettingsFromMemory(file_data, (size_t)file_data_size);\n\tIM_FREE(file_data);\n}\n\n// Zero-tolerance, no error reporting, cheap .ini parsing\n// Set ini_size==0 to let us use strlen(ini_data). Do not call this function with a 0 if your buffer is actually empty!\nvoid ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.Initialized);\n\t//IM_ASSERT(!g.WithinFrameScope && \"Cannot be called between NewFrame() and EndFrame()\");\n\t//IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);\n\n\t// For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).\n\t// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..\n\tif (ini_size == 0)\n\t\tini_size = strlen(ini_data);\n\tg.SettingsIniData.Buf.resize((int)ini_size + 1);\n\tchar* const buf = g.SettingsIniData.Buf.Data;\n\tchar* const buf_end = buf + ini_size;\n\tmemcpy(buf, ini_data, ini_size);\n\tbuf_end[0] = 0;\n\n\t// Call pre-read handlers\n\t// Some types will clear their data (e.g. dock information) some types will allow merge/override (window)\n\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\tif (handler.ReadInitFn != NULL)\n\t\t\thandler.ReadInitFn(&g, &handler);\n\n\tvoid* entry_data = NULL;\n\tImGuiSettingsHandler* entry_handler = NULL;\n\n\tchar* line_end = NULL;\n\tfor (char* line = buf; line < buf_end; line = line_end + 1)\n\t{\n\t\t// Skip new lines markers, then find end of the line\n\t\twhile (*line == '\\n' || *line == '\\r')\n\t\t\tline++;\n\t\tline_end = line;\n\t\twhile (line_end < buf_end && *line_end != '\\n' && *line_end != '\\r')\n\t\t\tline_end++;\n\t\tline_end[0] = 0;\n\t\tif (line[0] == ';')\n\t\t\tcontinue;\n\t\tif (line[0] == '[' && line_end > line && line_end[-1] == ']')\n\t\t{\n\t\t\t// Parse \"[Type][Name]\". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.\n\t\t\tline_end[-1] = 0;\n\t\t\tconst char* name_end = line_end - 1;\n\t\t\tconst char* type_start = line + 1;\n\t\t\tchar* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');\n\t\t\tconst char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;\n\t\t\tif (!type_end || !name_start)\n\t\t\t\tcontinue;\n\t\t\t*type_end = 0; // Overwrite first ']'\n\t\t\tname_start++;  // Skip second '['\n\t\t\tentry_handler = FindSettingsHandler(type_start);\n\t\t\tentry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;\n\t\t}\n\t\telse if (entry_handler != NULL && entry_data != NULL)\n\t\t{\n\t\t\t// Let type handler parse the line\n\t\t\tentry_handler->ReadLineFn(&g, entry_handler, entry_data, line);\n\t\t}\n\t}\n\tg.SettingsLoaded = true;\n\n\t// [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)\n\tmemcpy(buf, ini_data, ini_size);\n\n\t// Call post-read handlers\n\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\tif (handler.ApplyAllFn != NULL)\n\t\t\thandler.ApplyAllFn(&g, &handler);\n}\n\nvoid ImGui::SaveIniSettingsToDisk(const char* ini_filename)\n{\n\tImGuiContext& g = *GImGui;\n\tg.SettingsDirtyTimer = 0.0f;\n\tif (!ini_filename)\n\t\treturn;\n\n\tsize_t ini_data_size = 0;\n\tconst char* ini_data = SaveIniSettingsToMemory(&ini_data_size);\n\tImFileHandle f = ImFileOpen(ini_filename, \"wt\");\n\tif (!f)\n\t\treturn;\n\tImFileWrite(ini_data, sizeof(char), ini_data_size, f);\n\tImFileClose(f);\n}\n\n// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer\nconst char* ImGui::SaveIniSettingsToMemory(size_t* out_size)\n{\n\tImGuiContext& g = *GImGui;\n\tg.SettingsDirtyTimer = 0.0f;\n\tg.SettingsIniData.Buf.resize(0);\n\tg.SettingsIniData.Buf.push_back(0);\n\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\thandler.WriteAllFn(&g, &handler, &g.SettingsIniData);\n\tif (out_size)\n\t\t*out_size = (size_t)g.SettingsIniData.size();\n\treturn g.SettingsIniData.c_str();\n}\n\nImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)\n{\n\tImGuiContext& g = *GImGui;\n\n\tif (g.IO.ConfigDebugIniSettings == false)\n\t{\n\t\t// Skip to the \"###\" marker if any. We don't skip past to match the behavior of GetID()\n\t\t// Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier.\n\t\tif (const char* p = strstr(name, \"###\"))\n\t\t\tname = p;\n\t}\n\tconst size_t name_len = strlen(name);\n\n\t// Allocate chunk\n\tconst size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;\n\tImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);\n\tIM_PLACEMENT_NEW(settings) ImGuiWindowSettings();\n\tsettings->ID = ImHashStr(name, name_len);\n\tmemcpy(settings->GetName(), name, name_len + 1);   // Store with zero terminator\n\n\treturn settings;\n}\n\n// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names.\n// This is called once per window .ini entry + once per newly instantiated window.\nImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tfor (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))\n\t\tif (settings->ID == id && !settings->WantDelete)\n\t\t\treturn settings;\n\treturn NULL;\n}\n\n// This is faster if you are holding on a Window already as we don't need to perform a search.\nImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window)\n{\n\tImGuiContext& g = *GImGui;\n\tif (window->SettingsOffset != -1)\n\t\treturn g.SettingsWindows.ptr_from_offset(window->SettingsOffset);\n\treturn FindWindowSettingsByID(window->ID);\n}\n\n// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more.\nvoid ImGui::ClearWindowSettings(const char* name)\n{\n\t//IMGUI_DEBUG_LOG(\"ClearWindowSettings('%s')\\n\", name);\n\tImGuiWindow* window = FindWindowByName(name);\n\tif (window != NULL)\n\t{\n\t\twindow->Flags |= ImGuiWindowFlags_NoSavedSettings;\n\t\tInitOrLoadWindowSettings(window, NULL);\n\t}\n\tif (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name)))\n\t\tsettings->WantDelete = true;\n}\n\nstatic void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)\n{\n\tImGuiContext& g = *ctx;\n\tfor (ImGuiWindow* window : g.Windows)\n\t\twindow->SettingsOffset = -1;\n\tg.SettingsWindows.clear();\n}\n\nstatic void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)\n{\n\tImGuiID id = ImHashStr(name);\n\tImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id);\n\tif (settings)\n\t\t*settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry\n\telse\n\t\tsettings = ImGui::CreateNewWindowSettings(name);\n\tsettings->ID = id;\n\tsettings->WantApply = true;\n\treturn (void*)settings;\n}\n\nstatic void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)\n{\n\tImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;\n\tint x, y;\n\tint i;\n\tif (sscanf(line, \"Pos=%i,%i\", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); }\n\telse if (sscanf(line, \"Size=%i,%i\", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }\n\telse if (sscanf(line, \"Collapsed=%d\", &i) == 1) { settings->Collapsed = (i != 0); }\n}\n\n// Apply to existing windows (if any)\nstatic void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)\n{\n\tImGuiContext& g = *ctx;\n\tfor (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))\n\t\tif (settings->WantApply)\n\t\t{\n\t\t\tif (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))\n\t\t\t\tApplyWindowSettings(window, settings);\n\t\t\tsettings->WantApply = false;\n\t\t}\n}\n\nstatic void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)\n{\n\t// Gather data from windows that were active during this session\n\t// (if a window wasn't opened in this session we preserve its settings)\n\tImGuiContext& g = *ctx;\n\tfor (ImGuiWindow* window : g.Windows)\n\t{\n\t\tif (window->Flags & ImGuiWindowFlags_NoSavedSettings)\n\t\t\tcontinue;\n\n\t\tImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window);\n\t\tif (!settings)\n\t\t{\n\t\t\tsettings = ImGui::CreateNewWindowSettings(window->Name);\n\t\t\twindow->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);\n\t\t}\n\t\tIM_ASSERT(settings->ID == window->ID);\n\t\tsettings->Pos = ImVec2ih(window->Pos);\n\t\tsettings->Size = ImVec2ih(window->SizeFull);\n\n\t\tsettings->Collapsed = window->Collapsed;\n\t\tsettings->WantDelete = false;\n\t}\n\n\t// Write to text buffer\n\tbuf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve\n\tfor (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))\n\t{\n\t\tif (settings->WantDelete)\n\t\t\tcontinue;\n\t\tconst char* settings_name = settings->GetName();\n\t\tbuf->appendf(\"[%s][%s]\\n\", handler->TypeName, settings_name);\n\t\tbuf->appendf(\"Pos=%d,%d\\n\", settings->Pos.x, settings->Pos.y);\n\t\tbuf->appendf(\"Size=%d,%d\\n\", settings->Size.x, settings->Size.y);\n\t\tbuf->appendf(\"Collapsed=%d\\n\", settings->Collapsed);\n\t\tbuf->append(\"\\n\");\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] LOCALIZATION\n//-----------------------------------------------------------------------------\n\nvoid ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count)\n{\n\tImGuiContext& g = *GImGui;\n\tfor (int n = 0; n < count; n++)\n\t\tg.LocalizationTable[entries[n].Key] = entries[n].Text;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] VIEWPORTS, PLATFORM WINDOWS\n//-----------------------------------------------------------------------------\n// - GetMainViewport()\n// - SetWindowViewport() [Internal]\n// - UpdateViewportsNewFrame() [Internal]\n// (this section is more complete in the 'docking' branch)\n//-----------------------------------------------------------------------------\n\nImGuiViewport* ImGui::GetMainViewport()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.Viewports[0];\n}\n\nvoid ImGui::SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport)\n{\n\twindow->Viewport = viewport;\n}\n\n// Update viewports and monitor infos\nstatic void ImGui::UpdateViewportsNewFrame()\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.Viewports.Size == 1);\n\n\t// Update main viewport with current platform position.\n\t// FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent.\n\tImGuiViewportP* main_viewport = g.Viewports[0];\n\tmain_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp;\n\tmain_viewport->Pos = ImVec2(0.0f, 0.0f);\n\tmain_viewport->Size = g.IO.DisplaySize;\n\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t{\n\t\t// Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again.\n\t\tviewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;\n\t\tviewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;\n\t\tviewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);\n\t\tviewport->UpdateWorkRect();\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] DOCKING\n//-----------------------------------------------------------------------------\n\n// (this section is filled in the 'docking' branch)\n\n//-----------------------------------------------------------------------------\n// [SECTION] PLATFORM DEPENDENT HELPERS\n//-----------------------------------------------------------------------------\n\n#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)\n\n#ifdef _MSC_VER\n#pragma comment(lib, \"user32\")\n#pragma comment(lib, \"kernel32\")\n#endif\n\n// Win32 clipboard implementation\n// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()\nstatic const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)\n{\n\tImGuiContext& g = *(ImGuiContext*)user_data_ctx;\n\tg.ClipboardHandlerData.clear();\n\tif (!::OpenClipboard(NULL))\n\t\treturn NULL;\n\tHANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);\n\tif (wbuf_handle == NULL)\n\t{\n\t\t::CloseClipboard();\n\t\treturn NULL;\n\t}\n\tif (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))\n\t{\n\t\tint buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);\n\t\tg.ClipboardHandlerData.resize(buf_len);\n\t\t::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);\n\t}\n\t::GlobalUnlock(wbuf_handle);\n\t::CloseClipboard();\n\treturn g.ClipboardHandlerData.Data;\n}\n\nstatic void SetClipboardTextFn_DefaultImpl(void*, const char* text)\n{\n\tif (!::OpenClipboard(NULL))\n\t\treturn;\n\tconst int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);\n\tHGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));\n\tif (wbuf_handle == NULL)\n\t{\n\t\t::CloseClipboard();\n\t\treturn;\n\t}\n\tWCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);\n\t::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);\n\t::GlobalUnlock(wbuf_handle);\n\t::EmptyClipboard();\n\tif (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)\n\t\t::GlobalFree(wbuf_handle);\n\t::CloseClipboard();\n}\n\n#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)\n\n#include <Carbon/Carbon.h>  // Use old API to avoid need for separate .mm file\nstatic PasteboardRef main_clipboard = 0;\n\n// OSX clipboard implementation\n// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!\nstatic void SetClipboardTextFn_DefaultImpl(void*, const char* text)\n{\n\tif (!main_clipboard)\n\t\tPasteboardCreate(kPasteboardClipboard, &main_clipboard);\n\tPasteboardClear(main_clipboard);\n\tCFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));\n\tif (cf_data)\n\t{\n\t\tPasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR(\"public.utf8-plain-text\"), cf_data, 0);\n\t\tCFRelease(cf_data);\n\t}\n}\n\nstatic const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)\n{\n\tImGuiContext& g = *(ImGuiContext*)user_data_ctx;\n\tif (!main_clipboard)\n\t\tPasteboardCreate(kPasteboardClipboard, &main_clipboard);\n\tPasteboardSynchronize(main_clipboard);\n\n\tItemCount item_count = 0;\n\tPasteboardGetItemCount(main_clipboard, &item_count);\n\tfor (ItemCount i = 0; i < item_count; i++)\n\t{\n\t\tPasteboardItemID item_id = 0;\n\t\tPasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);\n\t\tCFArrayRef flavor_type_array = 0;\n\t\tPasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);\n\t\tfor (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)\n\t\t{\n\t\t\tCFDataRef cf_data;\n\t\t\tif (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR(\"public.utf8-plain-text\"), &cf_data) == noErr)\n\t\t\t{\n\t\t\t\tg.ClipboardHandlerData.clear();\n\t\t\t\tint length = (int)CFDataGetLength(cf_data);\n\t\t\t\tg.ClipboardHandlerData.resize(length + 1);\n\t\t\t\tCFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);\n\t\t\t\tg.ClipboardHandlerData[length] = 0;\n\t\t\t\tCFRelease(cf_data);\n\t\t\t\treturn g.ClipboardHandlerData.Data;\n\t\t\t}\n\t\t}\n\t}\n\treturn NULL;\n}\n\n#else\n\n// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.\nstatic const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)\n{\n\tImGuiContext& g = *(ImGuiContext*)user_data_ctx;\n\treturn g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();\n}\n\nstatic void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text)\n{\n\tImGuiContext& g = *(ImGuiContext*)user_data_ctx;\n\tg.ClipboardHandlerData.clear();\n\tconst char* text_end = text + strlen(text);\n\tg.ClipboardHandlerData.resize((int)(text_end - text) + 1);\n\tmemcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));\n\tg.ClipboardHandlerData[(int)(text_end - text)] = 0;\n}\n\n#endif\n\n// Win32 API IME support (for Asian languages, etc.)\n#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)\n\n#include <imm.h>\n#ifdef _MSC_VER\n#pragma comment(lib, \"imm32\")\n#endif\n\nstatic void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)\n{\n\t// Notify OS Input Method Editor of text input position\n\tHWND hwnd = (HWND)viewport->PlatformHandleRaw;\n\tif (hwnd == 0)\n\t\treturn;\n\n\t//::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);\n\tif (HIMC himc = ::ImmGetContext(hwnd))\n\t{\n\t\tCOMPOSITIONFORM composition_form = {};\n\t\tcomposition_form.ptCurrentPos.x = (LONG)data->InputPos.x;\n\t\tcomposition_form.ptCurrentPos.y = (LONG)data->InputPos.y;\n\t\tcomposition_form.dwStyle = CFS_FORCE_POSITION;\n\t\t::ImmSetCompositionWindow(himc, &composition_form);\n\t\tCANDIDATEFORM candidate_form = {};\n\t\tcandidate_form.dwStyle = CFS_CANDIDATEPOS;\n\t\tcandidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;\n\t\tcandidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;\n\t\t::ImmSetCandidateWindow(himc, &candidate_form);\n\t\t::ImmReleaseContext(hwnd, himc);\n\t}\n}\n\n#else\n\nstatic void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {}\n\n#endif\n\n//-----------------------------------------------------------------------------\n// [SECTION] METRICS/DEBUGGER WINDOW\n//-----------------------------------------------------------------------------\n// - RenderViewportThumbnail() [Internal]\n// - RenderViewportsThumbnails() [Internal]\n// - DebugTextEncoding()\n// - MetricsHelpMarker() [Internal]\n// - ShowFontAtlas() [Internal]\n// - ShowMetricsWindow()\n// - DebugNodeColumns() [Internal]\n// - DebugNodeDrawList() [Internal]\n// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal]\n// - DebugNodeFont() [Internal]\n// - DebugNodeFontGlyph() [Internal]\n// - DebugNodeStorage() [Internal]\n// - DebugNodeTabBar() [Internal]\n// - DebugNodeViewport() [Internal]\n// - DebugNodeWindow() [Internal]\n// - DebugNodeWindowSettings() [Internal]\n// - DebugNodeWindowsList() [Internal]\n// - DebugNodeWindowsListByBeginStackParent() [Internal]\n//-----------------------------------------------------------------------------\n\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\nvoid ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tImVec2 scale = bb.GetSize() / viewport->Size;\n\tImVec2 off = bb.Min - viewport->Pos * scale;\n\tfloat alpha_mul = 1.0f;\n\twindow->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));\n\tfor (ImGuiWindow* thumb_window : g.Windows)\n\t{\n\t\tif (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))\n\t\t\tcontinue;\n\n\t\tImRect thumb_r = thumb_window->Rect();\n\t\tImRect title_r = thumb_window->TitleBarRect();\n\t\tthumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale));\n\t\ttitle_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0, 5)); // Exaggerate title bar height\n\t\tthumb_r.ClipWithFull(bb);\n\t\ttitle_r.ClipWithFull(bb);\n\t\tconst bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);\n\t\twindow->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul));\n\t\twindow->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul));\n\t\twindow->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul));\n\t\twindow->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name));\n\t}\n\tdraw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul));\n}\n\nstatic void RenderViewportsThumbnails()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports.\n\tfloat SCALE = 1.0f / 8.0f;\n\tImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\tbb_full.Add(viewport->GetMainRect());\n\tImVec2 p = window->DC.CursorPos;\n\tImVec2 off = p - bb_full.Min * SCALE;\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t{\n\t\tImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);\n\t\tImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);\n\t}\n\tImGui::Dummy(bb_full.GetSize() * SCALE);\n}\n\n// Draw an arbitrary US keyboard layout to visualize translated keys\nvoid ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list)\n{\n\tconst ImVec2 key_size = ImVec2(35.0f, 35.0f);\n\tconst float  key_rounding = 3.0f;\n\tconst ImVec2 key_face_size = ImVec2(25.0f, 25.0f);\n\tconst ImVec2 key_face_pos = ImVec2(5.0f, 3.0f);\n\tconst float  key_face_rounding = 2.0f;\n\tconst ImVec2 key_label_pos = ImVec2(7.0f, 4.0f);\n\tconst ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);\n\tconst float  key_row_offset = 9.0f;\n\n\tImVec2 board_min = GetCursorScreenPos();\n\tImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);\n\tImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y);\n\n\tstruct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; };\n\tconst KeyLayoutData keys_to_display[] =\n\t{\n\t\t{ 0, 0, \"\", ImGuiKey_Tab },      { 0, 1, \"Q\", ImGuiKey_Q }, { 0, 2, \"W\", ImGuiKey_W }, { 0, 3, \"E\", ImGuiKey_E }, { 0, 4, \"R\", ImGuiKey_R },\n\t\t{ 1, 0, \"\", ImGuiKey_CapsLock }, { 1, 1, \"A\", ImGuiKey_A }, { 1, 2, \"S\", ImGuiKey_S }, { 1, 3, \"D\", ImGuiKey_D }, { 1, 4, \"F\", ImGuiKey_F },\n\t\t{ 2, 0, \"\", ImGuiKey_LeftShift },{ 2, 1, \"Z\", ImGuiKey_Z }, { 2, 2, \"X\", ImGuiKey_X }, { 2, 3, \"C\", ImGuiKey_C }, { 2, 4, \"V\", ImGuiKey_V }\n\t};\n\n\t// Elements rendered manually via ImDrawList API are not clipped automatically.\n\t// While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view.\n\tDummy(board_max - board_min);\n\tif (!IsItemVisible())\n\t\treturn;\n\tdraw_list->PushClipRect(board_min, board_max, true);\n\tfor (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++)\n\t{\n\t\tconst KeyLayoutData* key_data = &keys_to_display[n];\n\t\tImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y);\n\t\tImVec2 key_max = key_min + key_size;\n\t\tdraw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding);\n\t\tdraw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);\n\t\tImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);\n\t\tImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);\n\t\tdraw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);\n\t\tdraw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);\n\t\tImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);\n\t\tdraw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);\n\t\tif (IsKeyDown(key_data->Key))\n\t\t\tdraw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding);\n\t}\n\tdraw_list->PopClipRect();\n}\n\n// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct.\nvoid ImGui::DebugTextEncoding(const char* str)\n{\n\tText(\"Text: \\\"%s\\\"\", str);\n\tif (!BeginTable(\"##DebugTextEncoding\", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable))\n\t\treturn;\n\tTableSetupColumn(\"Offset\");\n\tTableSetupColumn(\"UTF-8\");\n\tTableSetupColumn(\"Glyph\");\n\tTableSetupColumn(\"Codepoint\");\n\tTableHeadersRow();\n\tfor (const char* p = str; *p != 0; )\n\t{\n\t\tunsigned int c;\n\t\tconst int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL);\n\t\tTableNextColumn();\n\t\tText(\"%d\", (int)(p - str));\n\t\tTableNextColumn();\n\t\tfor (int byte_index = 0; byte_index < c_utf8_len; byte_index++)\n\t\t{\n\t\t\tif (byte_index > 0)\n\t\t\t\tSameLine();\n\t\t\tText(\"0x%02X\", (int)(unsigned char)p[byte_index]);\n\t\t}\n\t\tTableNextColumn();\n\t\tif (GetFont()->FindGlyphNoFallback((ImWchar)c))\n\t\t\tTextUnformatted(p, p + c_utf8_len);\n\t\telse\n\t\t\tTextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? \"[invalid]\" : \"[missing]\");\n\t\tTableNextColumn();\n\t\tText(\"U+%04X\", (int)c);\n\t\tp += c_utf8_len;\n\t}\n\tEndTable();\n}\n\n// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.\nstatic void MetricsHelpMarker(const char* desc)\n{\n\tImGui::TextDisabled(\"(?)\");\n\tif (ImGui::BeginItemTooltip())\n\t{\n\t\tImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);\n\t\tImGui::TextUnformatted(desc);\n\t\tImGui::PopTextWrapPos();\n\t\tImGui::EndTooltip();\n\t}\n}\n\n// [DEBUG] List fonts in a font atlas and display its texture\nvoid ImGui::ShowFontAtlas(ImFontAtlas* atlas)\n{\n\tfor (ImFont* font : atlas->Fonts)\n\t{\n\t\tPushID(font);\n\t\tDebugNodeFont(font);\n\t\tPopID();\n\t}\n\tif (TreeNode(\"Font Atlas\", \"Font Atlas (%dx%d pixels)\", atlas->TexWidth, atlas->TexHeight))\n\t{\n\t\tImGuiContext& g = *GImGui;\n\t\tImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;\n\t\tCheckbox(\"Tint with Text Color\", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons\n\t\tImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);\n\t\tImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border);\n\t\tImage(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);\n\t\tTreePop();\n\t}\n}\n\nvoid ImGui::ShowMetricsWindow(bool* p_open)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\tImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;\n\tif (cfg->ShowDebugLog)\n\t\tShowDebugLogWindow(&cfg->ShowDebugLog);\n\tif (cfg->ShowStackTool)\n\t\tShowStackToolWindow(&cfg->ShowStackTool);\n\n\tif (!Begin(\"Dear ImGui Metrics/Debugger\", p_open) || GetCurrentWindow()->BeginCount > 1)\n\t{\n\t\tEnd();\n\t\treturn;\n\t}\n\n\t// Basic info\n\tText(\"Dear ImGui %s\", GetVersion());\n\tText(\"Application average %.3f ms/frame (%.1f FPS)\", 1000.0f / io.Framerate, io.Framerate);\n\tText(\"%d vertices, %d indices (%d triangles)\", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);\n\tText(\"%d visible windows, %d active allocations\", io.MetricsRenderWindows, io.MetricsActiveAllocations);\n\t//SameLine(); if (SmallButton(\"GC\")) { g.GcCompactAll = true; }\n\n\tSeparator();\n\n\t// Debugging enums\n\tenum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type\n\tconst char* wrt_rects_names[WRT_Count] = { \"OuterRect\", \"OuterRectClipped\", \"InnerRect\", \"InnerClipRect\", \"WorkRect\", \"Content\", \"ContentIdeal\", \"ContentRegionRect\" };\n\tenum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type\n\tconst char* trt_rects_names[TRT_Count] = { \"OuterRect\", \"InnerRect\", \"WorkRect\", \"HostClipRect\", \"InnerClipRect\", \"BackgroundClipRect\", \"ColumnsRect\", \"ColumnsWorkRect\", \"ColumnsClipRect\", \"ColumnsContentHeadersUsed\", \"ColumnsContentHeadersIdeal\", \"ColumnsContentFrozen\", \"ColumnsContentUnfrozen\" };\n\tif (cfg->ShowWindowsRectsType < 0)\n\t\tcfg->ShowWindowsRectsType = WRT_WorkRect;\n\tif (cfg->ShowTablesRectsType < 0)\n\t\tcfg->ShowTablesRectsType = TRT_WorkRect;\n\n\tstruct Funcs\n\t{\n\t\tstatic ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)\n\t\t{\n\t\t\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance\n\t\t\tif (rect_type == TRT_OuterRect) { return table->OuterRect; }\n\t\t\telse if (rect_type == TRT_InnerRect) { return table->InnerRect; }\n\t\t\telse if (rect_type == TRT_WorkRect) { return table->WorkRect; }\n\t\t\telse if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }\n\t\t\telse if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }\n\t\t\telse if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }\n\t\t\telse if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); }\n\t\t\telse if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }\n\t\t\telse if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }\n\t\t\telse if (rect_type == TRT_ColumnsContentHeadersUsed) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate\n\t\t\telse if (rect_type == TRT_ColumnsContentHeadersIdeal) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }\n\t\t\telse if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); }\n\t\t\telse if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }\n\t\t\tIM_ASSERT(0);\n\t\t\treturn ImRect();\n\t\t}\n\n\t\tstatic ImRect GetWindowRect(ImGuiWindow* window, int rect_type)\n\t\t{\n\t\t\tif (rect_type == WRT_OuterRect) { return window->Rect(); }\n\t\t\telse if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }\n\t\t\telse if (rect_type == WRT_InnerRect) { return window->InnerRect; }\n\t\t\telse if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }\n\t\t\telse if (rect_type == WRT_WorkRect) { return window->WorkRect; }\n\t\t\telse if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }\n\t\t\telse if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); }\n\t\t\telse if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; }\n\t\t\tIM_ASSERT(0);\n\t\t\treturn ImRect();\n\t\t}\n\t};\n\n\t// Tools\n\tif (TreeNode(\"Tools\"))\n\t{\n\t\tbool show_encoding_viewer = TreeNode(\"UTF-8 Encoding viewer\");\n\t\tSameLine();\n\t\tMetricsHelpMarker(\"You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.\");\n\t\tif (show_encoding_viewer)\n\t\t{\n\t\t\tstatic char buf[100] = \"\";\n\t\t\tSetNextItemWidth(-FLT_MIN);\n\t\t\tInputText(\"##Text\", buf, IM_ARRAYSIZE(buf));\n\t\t\tif (buf[0] != 0)\n\t\t\t\tDebugTextEncoding(buf);\n\t\t\tTreePop();\n\t\t}\n\n\t\t// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.\n\t\tif (Checkbox(\"Show Item Picker\", &g.DebugItemPickerActive) && g.DebugItemPickerActive)\n\t\t\tDebugStartItemPicker();\n\t\tSameLine();\n\t\tMetricsHelpMarker(\"Will call the IM_DEBUG_BREAK() macro to break in debugger.\\nWarning: If you don't have a debugger attached, this will probably crash.\");\n\n\t\t// Stack Tool is your best friend!\n\t\tCheckbox(\"Show Debug Log\", &cfg->ShowDebugLog);\n\t\tSameLine();\n\t\tMetricsHelpMarker(\"You can also call ImGui::ShowDebugLogWindow() from your code.\");\n\n\t\t// Stack Tool is your best friend!\n\t\tCheckbox(\"Show Stack Tool\", &cfg->ShowStackTool);\n\t\tSameLine();\n\t\tMetricsHelpMarker(\"You can also call ImGui::ShowStackToolWindow() from your code.\");\n\n\t\tCheckbox(\"Show windows begin order\", &cfg->ShowWindowsBeginOrder);\n\t\tCheckbox(\"Show windows rectangles\", &cfg->ShowWindowsRects);\n\t\tSameLine();\n\t\tSetNextItemWidth(GetFontSize() * 12);\n\t\tcfg->ShowWindowsRects |= Combo(\"##show_windows_rect_type\", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count);\n\t\tif (cfg->ShowWindowsRects && g.NavWindow != NULL)\n\t\t{\n\t\t\tBulletText(\"'%s':\", g.NavWindow->Name);\n\t\t\tIndent();\n\t\t\tfor (int rect_n = 0; rect_n < WRT_Count; rect_n++)\n\t\t\t{\n\t\t\t\tImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);\n\t\t\t\tText(\"(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s\", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]);\n\t\t\t}\n\t\t\tUnindent();\n\t\t}\n\n\t\tCheckbox(\"Show tables rectangles\", &cfg->ShowTablesRects);\n\t\tSameLine();\n\t\tSetNextItemWidth(GetFontSize() * 12);\n\t\tcfg->ShowTablesRects |= Combo(\"##show_table_rects_type\", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);\n\t\tif (cfg->ShowTablesRects && g.NavWindow != NULL)\n\t\t{\n\t\t\tfor (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)\n\t\t\t{\n\t\t\t\tImGuiTable* table = g.Tables.TryGetMapData(table_n);\n\t\t\t\tif (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tBulletText(\"Table 0x%08X (%d columns, in '%s')\", table->ID, table->ColumnsCount, table->OuterWindow->Name);\n\t\t\t\tif (IsItemHovered())\n\t\t\t\t\tGetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);\n\t\t\t\tIndent();\n\t\t\t\tchar buf[128];\n\t\t\t\tfor (int rect_n = 0; rect_n < TRT_Count; rect_n++)\n\t\t\t\t{\n\t\t\t\t\tif (rect_n >= TRT_ColumnsRect)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tImRect r = Funcs::GetTableRect(table, rect_n, column_n);\n\t\t\t\t\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s\", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]);\n\t\t\t\t\t\t\tSelectable(buf);\n\t\t\t\t\t\t\tif (IsItemHovered())\n\t\t\t\t\t\t\t\tGetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tImRect r = Funcs::GetTableRect(table, rect_n, -1);\n\t\t\t\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s\", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]);\n\t\t\t\t\t\tSelectable(buf);\n\t\t\t\t\t\tif (IsItemHovered())\n\t\t\t\t\t\t\tGetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tUnindent();\n\t\t\t}\n\t\t}\n\n\t\tCheckbox(\"Debug Begin/BeginChild return value\", &io.ConfigDebugBeginReturnValueLoop);\n\t\tSameLine();\n\t\tMetricsHelpMarker(\"Some calls to Begin()/BeginChild() will return false.\\n\\nWill cycle through window depths then repeat. Windows should be flickering while running.\");\n\n\t\tTreePop();\n\t}\n\n\t// Windows\n\tif (TreeNode(\"Windows\", \"Windows (%d)\", g.Windows.Size))\n\t{\n\t\t//SetNextItemOpen(true, ImGuiCond_Once);\n\t\tDebugNodeWindowsList(&g.Windows, \"By display order\");\n\t\tDebugNodeWindowsList(&g.WindowsFocusOrder, \"By focus order (root windows)\");\n\t\tif (TreeNode(\"By submission order (begin stack)\"))\n\t\t{\n\t\t\t// Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!\n\t\t\tImVector<ImGuiWindow*>& temp_buffer = g.WindowsTempSortBuffer;\n\t\t\ttemp_buffer.resize(0);\n\t\t\tfor (ImGuiWindow* window : g.Windows)\n\t\t\t\tif (window->LastFrameActive + 1 >= g.FrameCount)\n\t\t\t\t\ttemp_buffer.push_back(window);\n\t\t\tstruct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const*)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };\n\t\t\tImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);\n\t\t\tDebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);\n\t\t\tTreePop();\n\t\t}\n\n\t\tTreePop();\n\t}\n\n\t// DrawLists\n\tint drawlist_count = 0;\n\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\tdrawlist_count += viewport->DrawDataP.CmdLists.Size;\n\tif (TreeNode(\"DrawLists\", \"DrawLists (%d)\", drawlist_count))\n\t{\n\t\tCheckbox(\"Show ImDrawCmd mesh when hovering\", &cfg->ShowDrawCmdMesh);\n\t\tCheckbox(\"Show ImDrawCmd bounding boxes when hovering\", &cfg->ShowDrawCmdBoundingBoxes);\n\t\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\t\tfor (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)\n\t\t\t\tDebugNodeDrawList(NULL, viewport, draw_list, \"DrawList\");\n\t\tTreePop();\n\t}\n\n\t// Viewports\n\tif (TreeNode(\"Viewports\", \"Viewports (%d)\", g.Viewports.Size))\n\t{\n\t\tIndent(GetTreeNodeToLabelSpacing());\n\t\tRenderViewportsThumbnails();\n\t\tUnindent(GetTreeNodeToLabelSpacing());\n\t\tfor (ImGuiViewportP* viewport : g.Viewports)\n\t\t\tDebugNodeViewport(viewport);\n\t\tTreePop();\n\t}\n\n\t// Details for Popups\n\tif (TreeNode(\"Popups\", \"Popups (%d)\", g.OpenPopupStack.Size))\n\t{\n\t\tfor (const ImGuiPopupData& popup_data : g.OpenPopupStack)\n\t\t{\n\t\t\t// As it's difficult to interact with tree nodes while popups are open, we display everything inline.\n\t\t\tImGuiWindow* window = popup_data.Window;\n\t\t\tBulletText(\"PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'\",\n\t\t\t\tpopup_data.PopupId, window ? window->Name : \"NULL\", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? \"Child;\" : \"\", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? \"Menu;\" : \"\",\n\t\t\t\tpopup_data.BackupNavWindow ? popup_data.BackupNavWindow->Name : \"NULL\", window && window->ParentWindow ? window->ParentWindow->Name : \"NULL\");\n\t\t}\n\t\tTreePop();\n\t}\n\n\t// Details for TabBars\n\tif (TreeNode(\"TabBars\", \"Tab Bars (%d)\", g.TabBars.GetAliveCount()))\n\t{\n\t\tfor (int n = 0; n < g.TabBars.GetMapSize(); n++)\n\t\t\tif (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n))\n\t\t\t{\n\t\t\t\tPushID(tab_bar);\n\t\t\t\tDebugNodeTabBar(tab_bar, \"TabBar\");\n\t\t\t\tPopID();\n\t\t\t}\n\t\tTreePop();\n\t}\n\n\t// Details for Tables\n\tif (TreeNode(\"Tables\", \"Tables (%d)\", g.Tables.GetAliveCount()))\n\t{\n\t\tfor (int n = 0; n < g.Tables.GetMapSize(); n++)\n\t\t\tif (ImGuiTable* table = g.Tables.TryGetMapData(n))\n\t\t\t\tDebugNodeTable(table);\n\t\tTreePop();\n\t}\n\n\t// Details for Fonts\n\tImFontAtlas* atlas = g.IO.Fonts;\n\tif (TreeNode(\"Fonts\", \"Fonts (%d)\", atlas->Fonts.Size))\n\t{\n\t\tShowFontAtlas(atlas);\n\t\tTreePop();\n\t}\n\n\t// Details for InputText\n\tif (TreeNode(\"InputText\"))\n\t{\n\t\tDebugNodeInputTextState(&g.InputTextState);\n\t\tTreePop();\n\t}\n\n\t// Details for Docking\n#ifdef IMGUI_HAS_DOCK\n\tif (TreeNode(\"Docking\"))\n\t{\n\t\tTreePop();\n\t}\n#endif // #ifdef IMGUI_HAS_DOCK\n\n\t// Settings\n\tif (TreeNode(\"Settings\"))\n\t{\n\t\tif (SmallButton(\"Clear\"))\n\t\t\tClearIniSettings();\n\t\tSameLine();\n\t\tif (SmallButton(\"Save to memory\"))\n\t\t\tSaveIniSettingsToMemory();\n\t\tSameLine();\n\t\tif (SmallButton(\"Save to disk\"))\n\t\t\tSaveIniSettingsToDisk(g.IO.IniFilename);\n\t\tSameLine();\n\t\tif (g.IO.IniFilename)\n\t\t\tText(\"\\\"%s\\\"\", g.IO.IniFilename);\n\t\telse\n\t\t\tTextUnformatted(\"<NULL>\");\n\t\tCheckbox(\"io.ConfigDebugIniSettings\", &io.ConfigDebugIniSettings);\n\t\tText(\"SettingsDirtyTimer %.2f\", g.SettingsDirtyTimer);\n\t\tif (TreeNode(\"SettingsHandlers\", \"Settings handlers: (%d)\", g.SettingsHandlers.Size))\n\t\t{\n\t\t\tfor (ImGuiSettingsHandler& handler : g.SettingsHandlers)\n\t\t\t\tBulletText(\"\\\"%s\\\"\", handler.TypeName);\n\t\t\tTreePop();\n\t\t}\n\t\tif (TreeNode(\"SettingsWindows\", \"Settings packed data: Windows: %d bytes\", g.SettingsWindows.size()))\n\t\t{\n\t\t\tfor (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))\n\t\t\t\tDebugNodeWindowSettings(settings);\n\t\t\tTreePop();\n\t\t}\n\n\t\tif (TreeNode(\"SettingsTables\", \"Settings packed data: Tables: %d bytes\", g.SettingsTables.size()))\n\t\t{\n\t\t\tfor (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))\n\t\t\t\tDebugNodeTableSettings(settings);\n\t\t\tTreePop();\n\t\t}\n\n#ifdef IMGUI_HAS_DOCK\n#endif // #ifdef IMGUI_HAS_DOCK\n\n\t\tif (TreeNode(\"SettingsIniData\", \"Settings unpacked data (.ini): %d bytes\", g.SettingsIniData.size()))\n\t\t{\n\t\t\tInputTextMultiline(\"##Ini\", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly);\n\t\t\tTreePop();\n\t\t}\n\t\tTreePop();\n\t}\n\n\tif (TreeNode(\"Inputs\"))\n\t{\n\t\tText(\"KEYBOARD/GAMEPAD/MOUSE KEYS\");\n\t\t{\n\t\t\t// We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends.\n\t\t\t// User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.\n\t\t\tIndent();\n#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO\n\t\t\tstruct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };\n#else\n\t\t\tstruct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array\n\t\t\t//Text(\"Legacy raw:\");      for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text(\"\\\"%s\\\" %d\", GetKeyName(key), key); } }\n#endif\n\t\t\tText(\"Keys down:\");         for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue;     SameLine(); Text(IsNamedKey(key) ? \"\\\"%s\\\"\" : \"\\\"%s\\\" %d\", GetKeyName(key), key); SameLine(); Text(\"(%.02f)\", GetKeyData(key)->DownDuration); }\n\t\t\tText(\"Keys pressed:\");      for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue;  SameLine(); Text(IsNamedKey(key) ? \"\\\"%s\\\"\" : \"\\\"%s\\\" %d\", GetKeyName(key), key); }\n\t\t\tText(\"Keys released:\");     for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? \"\\\"%s\\\"\" : \"\\\"%s\\\" %d\", GetKeyName(key), key); }\n\t\t\tText(\"Keys mods: %s%s%s%s\", io.KeyCtrl ? \"CTRL \" : \"\", io.KeyShift ? \"SHIFT \" : \"\", io.KeyAlt ? \"ALT \" : \"\", io.KeySuper ? \"SUPER \" : \"\");\n\t\t\tText(\"Chars queue:\");       for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text(\"\\'%c\\' (0x%04X)\", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.\n\t\t\tDebugRenderKeyboardPreview(GetWindowDrawList());\n\t\t\tUnindent();\n\t\t}\n\n\t\tText(\"MOUSE STATE\");\n\t\t{\n\t\t\tIndent();\n\t\t\tif (IsMousePosValid())\n\t\t\t\tText(\"Mouse pos: (%g, %g)\", io.MousePos.x, io.MousePos.y);\n\t\t\telse\n\t\t\t\tText(\"Mouse pos: <INVALID>\");\n\t\t\tText(\"Mouse delta: (%g, %g)\", io.MouseDelta.x, io.MouseDelta.y);\n\t\t\tint count = IM_ARRAYSIZE(io.MouseDown);\n\t\t\tText(\"Mouse down:\");     for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text(\"b%d (%.02f secs)\", i, io.MouseDownDuration[i]); }\n\t\t\tText(\"Mouse clicked:\");  for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text(\"b%d (%d)\", i, io.MouseClickedCount[i]); }\n\t\t\tText(\"Mouse released:\"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text(\"b%d\", i); }\n\t\t\tText(\"Mouse wheel: %.1f\", io.MouseWheel);\n\t\t\tText(\"MouseStationaryTimer: %.2f\", g.MouseStationaryTimer);\n\t\t\tText(\"Mouse source: %s\", GetMouseSourceName(io.MouseSource));\n\t\t\tText(\"Pen Pressure: %.1f\", io.PenPressure); // Note: currently unused\n\t\t\tUnindent();\n\t\t}\n\n\t\tText(\"MOUSE WHEELING\");\n\t\t{\n\t\t\tIndent();\n\t\t\tText(\"WheelingWindow: '%s'\", g.WheelingWindow ? g.WheelingWindow->Name : \"NULL\");\n\t\t\tText(\"WheelingWindowReleaseTimer: %.2f\", g.WheelingWindowReleaseTimer);\n\t\t\tText(\"WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s\", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? \"X\" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? \"Y\" : \"<none>\");\n\t\t\tUnindent();\n\t\t}\n\n\t\tText(\"KEY OWNERS\");\n\t\t{\n\t\t\tIndent();\n\t\t\tif (BeginListBox(\"##owners\", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))\n\t\t\t{\n\t\t\t\tfor (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))\n\t\t\t\t{\n\t\t\t\t\tImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);\n\t\t\t\t\tif (owner_data->OwnerCurr == ImGuiKeyOwner_None)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tText(\"%s: 0x%08X%s\", GetKeyName(key), owner_data->OwnerCurr,\n\t\t\t\t\t\towner_data->LockUntilRelease ? \" LockUntilRelease\" : owner_data->LockThisFrame ? \" LockThisFrame\" : \"\");\n\t\t\t\t\tDebugLocateItemOnHover(owner_data->OwnerCurr);\n\t\t\t\t}\n\t\t\t\tEndListBox();\n\t\t\t}\n\t\t\tUnindent();\n\t\t}\n\t\tText(\"SHORTCUT ROUTING\");\n\t\t{\n\t\t\tIndent();\n\t\t\tif (BeginListBox(\"##routes\", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))\n\t\t\t{\n\t\t\t\tfor (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))\n\t\t\t\t{\n\t\t\t\t\tImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;\n\t\t\t\t\tfor (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; )\n\t\t\t\t\t{\n\t\t\t\t\t\tchar key_chord_name[64];\n\t\t\t\t\t\tImGuiKeyRoutingData* routing_data = &rt->Entries[idx];\n\t\t\t\t\t\tGetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name));\n\t\t\t\t\t\tText(\"%s: 0x%08X\", key_chord_name, routing_data->RoutingCurr);\n\t\t\t\t\t\tDebugLocateItemOnHover(routing_data->RoutingCurr);\n\t\t\t\t\t\tidx = routing_data->NextEntryIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tEndListBox();\n\t\t\t}\n\t\t\tText(\"(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)\", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);\n\t\t\tUnindent();\n\t\t}\n\t\tTreePop();\n\t}\n\n\tif (TreeNode(\"Internal state\"))\n\t{\n\t\tText(\"WINDOWING\");\n\t\tIndent();\n\t\tText(\"HoveredWindow: '%s'\", g.HoveredWindow ? g.HoveredWindow->Name : \"NULL\");\n\t\tText(\"HoveredWindow->Root: '%s'\", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : \"NULL\");\n\t\tText(\"HoveredWindowUnderMovingWindow: '%s'\", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : \"NULL\");\n\t\tText(\"MovingWindow: '%s'\", g.MovingWindow ? g.MovingWindow->Name : \"NULL\");\n\t\tUnindent();\n\n\t\tText(\"ITEMS\");\n\t\tIndent();\n\t\tText(\"ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s\", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource));\n\t\tDebugLocateItemOnHover(g.ActiveId);\n\t\tText(\"ActiveIdWindow: '%s'\", g.ActiveIdWindow ? g.ActiveIdWindow->Name : \"NULL\");\n\t\tText(\"ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X\", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);\n\t\tText(\"HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d\", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame\n\t\tText(\"HoverItemDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f\", g.HoverItemDelayId, g.HoverItemDelayTimer, g.HoverItemDelayClearTimer);\n\t\tText(\"DragDrop: %d, SourceId = 0x%08X, Payload \\\"%s\\\" (%d bytes)\", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);\n\t\tDebugLocateItemOnHover(g.DragDropPayload.SourceId);\n\t\tUnindent();\n\n\t\tText(\"NAV,FOCUS\");\n\t\tIndent();\n\t\tText(\"NavWindow: '%s'\", g.NavWindow ? g.NavWindow->Name : \"NULL\");\n\t\tText(\"NavId: 0x%08X, NavLayer: %d\", g.NavId, g.NavLayer);\n\t\tDebugLocateItemOnHover(g.NavId);\n\t\tText(\"NavInputSource: %s\", GetInputSourceName(g.NavInputSource));\n\t\tText(\"NavActive: %d, NavVisible: %d\", g.IO.NavActive, g.IO.NavVisible);\n\t\tText(\"NavActivateId/DownId/PressedId: %08X/%08X/%08X\", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId);\n\t\tText(\"NavActivateFlags: %04X\", g.NavActivateFlags);\n\t\tText(\"NavDisableHighlight: %d, NavDisableMouseHover: %d\", g.NavDisableHighlight, g.NavDisableMouseHover);\n\t\tText(\"NavFocusScopeId = 0x%08X\", g.NavFocusScopeId);\n\t\tText(\"NavWindowingTarget: '%s'\", g.NavWindowingTarget ? g.NavWindowingTarget->Name : \"NULL\");\n\t\tUnindent();\n\n\t\tTreePop();\n\t}\n\n\t// Overlay: Display windows Rectangles and Begin Order\n\tif (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)\n\t{\n\t\tfor (ImGuiWindow* window : g.Windows)\n\t\t{\n\t\t\tif (!window->WasActive)\n\t\t\t\tcontinue;\n\t\t\tImDrawList* draw_list = GetForegroundDrawList(window);\n\t\t\tif (cfg->ShowWindowsRects)\n\t\t\t{\n\t\t\t\tImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType);\n\t\t\t\tdraw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));\n\t\t\t}\n\t\t\tif (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow))\n\t\t\t{\n\t\t\t\tchar buf[32];\n\t\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"%d\", window->BeginOrderWithinContext);\n\t\t\t\tfloat font_size = GetFontSize();\n\t\t\t\tdraw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));\n\t\t\t\tdraw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Overlay: Display Tables Rectangles\n\tif (cfg->ShowTablesRects)\n\t{\n\t\tfor (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)\n\t\t{\n\t\t\tImGuiTable* table = g.Tables.TryGetMapData(table_n);\n\t\t\tif (table == NULL || table->LastFrameActive < g.FrameCount - 1)\n\t\t\t\tcontinue;\n\t\t\tImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);\n\t\t\tif (cfg->ShowTablesRectsType >= TRT_ColumnsRect)\n\t\t\t{\n\t\t\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\t\t{\n\t\t\t\t\tImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);\n\t\t\t\t\tImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);\n\t\t\t\t\tfloat thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;\n\t\t\t\t\tdraw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1);\n\t\t\t\tdraw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));\n\t\t\t}\n\t\t}\n\t}\n\n#ifdef IMGUI_HAS_DOCK\n\t// Overlay: Display Docking info\n\tif (show_docking_nodes && g.IO.KeyCtrl)\n\t{\n\t}\n#endif // #ifdef IMGUI_HAS_DOCK\n\n\tEnd();\n}\n\n// [DEBUG] Display contents of Columns\nvoid ImGui::DebugNodeColumns(ImGuiOldColumns* columns)\n{\n\tif (!TreeNode((void*)(uintptr_t)columns->ID, \"Columns Id: 0x%08X, Count: %d, Flags: 0x%04X\", columns->ID, columns->Count, columns->Flags))\n\t\treturn;\n\tBulletText(\"Width: %.1f (MinX: %.1f, MaxX: %.1f)\", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);\n\tfor (ImGuiOldColumnData& column : columns->Columns)\n\t\tBulletText(\"Column %02d: OffsetNorm %.3f (= %.1f px)\", (int)columns->Columns.index_from_ptr(&column), column.OffsetNorm, GetColumnOffsetFromNorm(columns, column.OffsetNorm));\n\tTreePop();\n}\n\n// [DEBUG] Display contents of ImDrawList\nvoid ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_UNUSED(viewport); // Used in docking branch\n\tImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;\n\tint cmd_count = draw_list->CmdBuffer.Size;\n\tif (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL)\n\t\tcmd_count--;\n\tbool node_open = TreeNode(draw_list, \"%s: '%s' %d vtx, %d indices, %d cmds\", label, draw_list->_OwnerName ? draw_list->_OwnerName : \"\", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count);\n\tif (draw_list == GetWindowDrawList())\n\t{\n\t\tSameLine();\n\t\tTextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), \"CURRENTLY APPENDING\"); // Can't display stats for active draw list! (we don't have the data double-buffered)\n\t\tif (node_open)\n\t\t\tTreePop();\n\t\treturn;\n\t}\n\n\tImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list\n\tif (window && IsItemHovered() && fg_draw_list)\n\t\tfg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));\n\tif (!node_open)\n\t\treturn;\n\n\tif (window && !window->WasActive)\n\t\tTextDisabled(\"Warning: owning Window is inactive. This DrawList is not being rendered!\");\n\n\tfor (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++)\n\t{\n\t\tif (pcmd->UserCallback)\n\t\t{\n\t\t\tBulletText(\"Callback %p, user_data %p\", pcmd->UserCallback, pcmd->UserCallbackData);\n\t\t\tcontinue;\n\t\t}\n\n\t\tchar buf[300];\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)\",\n\t\t\tpcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,\n\t\t\tpcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);\n\t\tbool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), \"%s\", buf);\n\t\tif (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list)\n\t\t\tDebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes);\n\t\tif (!pcmd_node_open)\n\t\t\tcontinue;\n\n\t\t// Calculate approximate coverage area (touched pixel count)\n\t\t// This will be in pixels squared as long there's no post-scaling happening to the renderer output.\n\t\tconst ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;\n\t\tconst ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset;\n\t\tfloat total_area = 0.0f;\n\t\tfor (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; )\n\t\t{\n\t\t\tImVec2 triangle[3];\n\t\t\tfor (int n = 0; n < 3; n++, idx_n++)\n\t\t\t\ttriangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos;\n\t\t\ttotal_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);\n\t\t}\n\n\t\t// Display vertex information summary. Hover to get all triangles drawn in wire-frame\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px\", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);\n\t\tSelectable(buf);\n\t\tif (IsItemHovered() && fg_draw_list)\n\t\t\tDebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false);\n\n\t\t// Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.\n\t\tImGuiListClipper clipper;\n\t\tclipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.\n\t\twhile (clipper.Step())\n\t\t\tfor (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)\n\t\t\t{\n\t\t\t\tchar* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf);\n\t\t\t\tImVec2 triangle[3];\n\t\t\t\tfor (int n = 0; n < 3; n++, idx_i++)\n\t\t\t\t{\n\t\t\t\t\tconst ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i];\n\t\t\t\t\ttriangle[n] = v.pos;\n\t\t\t\t\tbuf_p += ImFormatString(buf_p, buf_end - buf_p, \"%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\\n\",\n\t\t\t\t\t\t(n == 0) ? \"Vert:\" : \"     \", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);\n\t\t\t\t}\n\n\t\t\t\tSelectable(buf, false);\n\t\t\t\tif (fg_draw_list && IsItemHovered())\n\t\t\t\t{\n\t\t\t\t\tImDrawListFlags backup_flags = fg_draw_list->Flags;\n\t\t\t\t\tfg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.\n\t\t\t\t\tfg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f);\n\t\t\t\t\tfg_draw_list->Flags = backup_flags;\n\t\t\t\t}\n\t\t\t}\n\t\tTreePop();\n\t}\n\tTreePop();\n}\n\n// [DEBUG] Display mesh/aabb of a ImDrawCmd\nvoid ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)\n{\n\tIM_ASSERT(show_mesh || show_aabb);\n\n\t// Draw wire-frame version of all triangles\n\tImRect clip_rect = draw_cmd->ClipRect;\n\tImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);\n\tImDrawListFlags backup_flags = out_draw_list->Flags;\n\tout_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.\n\tfor (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; )\n\t{\n\t\tImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list\n\t\tImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;\n\n\t\tImVec2 triangle[3];\n\t\tfor (int n = 0; n < 3; n++, idx_n++)\n\t\t\tvtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));\n\t\tif (show_mesh)\n\t\t\tout_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles\n\t}\n\t// Draw bounding boxes\n\tif (show_aabb)\n\t{\n\t\tout_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU\n\t\tout_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles\n\t}\n\tout_draw_list->Flags = backup_flags;\n}\n\n// [DEBUG] Display details for a single font, called by ShowStyleEditor().\nvoid ImGui::DebugNodeFont(ImFont* font)\n{\n\tbool opened = TreeNode(font, \"Font: \\\"%s\\\"\\n%.2f px, %d glyphs, %d file(s)\",\n\t\tfont->ConfigData ? font->ConfigData[0].Name : \"\", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);\n\tSameLine();\n\tif (SmallButton(\"Set as default\"))\n\t\tGetIO().FontDefault = font;\n\tif (!opened)\n\t\treturn;\n\n\t// Display preview text\n\tPushFont(font);\n\tText(\"The quick brown fox jumps over the lazy dog\");\n\tPopFont();\n\n\t// Display details\n\tSetNextItemWidth(GetFontSize() * 8);\n\tDragFloat(\"Font scale\", &font->Scale, 0.005f, 0.3f, 2.0f, \"%.1f\");\n\tSameLine(); MetricsHelpMarker(\n\t\t\"Note than the default embedded font is NOT meant to be scaled.\\n\\n\"\n\t\t\"Font are currently rendered into bitmaps at a given size at the time of building the atlas. \"\n\t\t\"You may oversample them to get some flexibility with scaling. \"\n\t\t\"You can also render at multiple sizes and select which one to use at runtime.\\n\\n\"\n\t\t\"(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)\");\n\tText(\"Ascent: %f, Descent: %f, Height: %f\", font->Ascent, font->Descent, font->Ascent - font->Descent);\n\tchar c_str[5];\n\tText(\"Fallback character: '%s' (U+%04X)\", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);\n\tText(\"Ellipsis character: '%s' (U+%04X)\", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);\n\tconst int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface);\n\tText(\"Texture Area: about %d px ~%dx%d px\", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);\n\tfor (int config_i = 0; config_i < font->ConfigDataCount; config_i++)\n\t\tif (font->ConfigData)\n\t\t\tif (const ImFontConfig* cfg = &font->ConfigData[config_i])\n\t\t\t\tBulletText(\"Input %d: \\'%s\\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)\",\n\t\t\t\t\tconfig_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);\n\n\t// Display all glyphs of the fonts in separate pages of 256 characters\n\tif (TreeNode(\"Glyphs\", \"Glyphs (%d)\", font->Glyphs.Size))\n\t{\n\t\tImDrawList* draw_list = GetWindowDrawList();\n\t\tconst ImU32 glyph_col = GetColorU32(ImGuiCol_Text);\n\t\tconst float cell_size = font->FontSize * 1;\n\t\tconst float cell_spacing = GetStyle().ItemSpacing.y;\n\t\tfor (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)\n\t\t{\n\t\t\t// Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)\n\t\t\t// This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT\n\t\t\t// is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)\n\t\t\tif (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))\n\t\t\t{\n\t\t\t\tbase += 4096 - 256;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tint count = 0;\n\t\t\tfor (unsigned int n = 0; n < 256; n++)\n\t\t\t\tif (font->FindGlyphNoFallback((ImWchar)(base + n)))\n\t\t\t\t\tcount++;\n\t\t\tif (count <= 0)\n\t\t\t\tcontinue;\n\t\t\tif (!TreeNode((void*)(intptr_t)base, \"U+%04X..U+%04X (%d %s)\", base, base + 255, count, count > 1 ? \"glyphs\" : \"glyph\"))\n\t\t\t\tcontinue;\n\n\t\t\t// Draw a 16x16 grid of glyphs\n\t\t\tImVec2 base_pos = GetCursorScreenPos();\n\t\t\tfor (unsigned int n = 0; n < 256; n++)\n\t\t\t{\n\t\t\t\t// We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions\n\t\t\t\t// available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.\n\t\t\t\tImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));\n\t\t\t\tImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);\n\t\t\t\tconst ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));\n\t\t\t\tdraw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));\n\t\t\t\tif (!glyph)\n\t\t\t\t\tcontinue;\n\t\t\t\tfont->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));\n\t\t\t\tif (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip())\n\t\t\t\t{\n\t\t\t\t\tDebugNodeFontGlyph(font, glyph);\n\t\t\t\t\tEndTooltip();\n\t\t\t\t}\n\t\t\t}\n\t\t\tDummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));\n\t\t\tTreePop();\n\t\t}\n\t\tTreePop();\n\t}\n\tTreePop();\n}\n\nvoid ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph)\n{\n\tText(\"Codepoint: U+%04X\", glyph->Codepoint);\n\tSeparator();\n\tText(\"Visible: %d\", glyph->Visible);\n\tText(\"AdvanceX: %.1f\", glyph->AdvanceX);\n\tText(\"Pos: (%.2f,%.2f)->(%.2f,%.2f)\", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);\n\tText(\"UV: (%.3f,%.3f)->(%.3f,%.3f)\", glyph->U0, glyph->V0, glyph->U1, glyph->V1);\n}\n\n// [DEBUG] Display contents of ImGuiStorage\nvoid ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)\n{\n\tif (!TreeNode(label, \"%s: %d entries, %d bytes\", label, storage->Data.Size, storage->Data.size_in_bytes()))\n\t\treturn;\n\tfor (const ImGuiStorage::ImGuiStoragePair& p : storage->Data)\n\t\tBulletText(\"Key 0x%08X Value { i: %d }\", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.\n\tTreePop();\n}\n\n// [DEBUG] Display contents of ImGuiTabBar\nvoid ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)\n{\n\t// Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.\n\tchar buf[256];\n\tchar* p = buf;\n\tconst char* buf_end = buf + IM_ARRAYSIZE(buf);\n\tconst bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2);\n\tp += ImFormatString(p, buf_end - p, \"%s 0x%08X (%d tabs)%s  {\", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? \"\" : \" *Inactive*\");\n\tfor (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)\n\t{\n\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_n];\n\t\tp += ImFormatString(p, buf_end - p, \"%s'%s'\", tab_n > 0 ? \", \" : \"\", TabBarGetTabName(tab_bar, tab));\n\t}\n\tp += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? \" ... }\" : \" } \");\n\tif (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }\n\tbool open = TreeNode(label, \"%s\", buf);\n\tif (!is_active) { PopStyleColor(); }\n\tif (is_active && IsItemHovered())\n\t{\n\t\tImDrawList* draw_list = GetForegroundDrawList();\n\t\tdraw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));\n\t\tdraw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));\n\t\tdraw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));\n\t}\n\tif (open)\n\t{\n\t\tfor (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)\n\t\t{\n\t\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_n];\n\t\t\tPushID(tab);\n\t\t\tif (SmallButton(\"<\")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);\n\t\t\tif (SmallButton(\">\")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();\n\t\t\tText(\"%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f\",\n\t\t\t\ttab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth);\n\t\t\tPopID();\n\t\t}\n\t\tTreePop();\n\t}\n}\n\nvoid ImGui::DebugNodeViewport(ImGuiViewportP* viewport)\n{\n\tSetNextItemOpen(true, ImGuiCond_Once);\n\tif (TreeNode(\"viewport0\", \"Viewport #%d\", 0))\n\t{\n\t\tImGuiWindowFlags flags = viewport->Flags;\n\t\tBulletText(\"Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\",\n\t\t\tviewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,\n\t\t\tviewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y);\n\t\tBulletText(\"Flags: 0x%04X =%s%s%s\", viewport->Flags,\n\t\t\t(flags & ImGuiViewportFlags_IsPlatformWindow) ? \" IsPlatformWindow\" : \"\",\n\t\t\t(flags & ImGuiViewportFlags_IsPlatformMonitor) ? \" IsPlatformMonitor\" : \"\",\n\t\t\t(flags & ImGuiViewportFlags_OwnedByApp) ? \" OwnedByApp\" : \"\");\n\t\tfor (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)\n\t\t\tDebugNodeDrawList(NULL, viewport, draw_list, \"DrawList\");\n\t\tTreePop();\n\t}\n}\n\nvoid ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)\n{\n\tif (window == NULL)\n\t{\n\t\tBulletText(\"%s: NULL\", label);\n\t\treturn;\n\t}\n\n\tImGuiContext& g = *GImGui;\n\tconst bool is_active = window->WasActive;\n\tImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;\n\tif (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }\n\tconst bool open = TreeNodeEx(label, tree_node_flags, \"%s '%s'%s\", label, window->Name, is_active ? \"\" : \" *Inactive*\");\n\tif (!is_active) { PopStyleColor(); }\n\tif (IsItemHovered() && is_active)\n\t\tGetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));\n\tif (!open)\n\t\treturn;\n\n\tif (window->MemoryCompacted)\n\t\tTextDisabled(\"Note: some memory buffers have been compacted/freed.\");\n\n\tImGuiWindowFlags flags = window->Flags;\n\tDebugNodeDrawList(window, window->Viewport, window->DrawList, \"DrawList\");\n\tBulletText(\"Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)\", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y);\n\tBulletText(\"Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)\", flags,\n\t\t(flags & ImGuiWindowFlags_ChildWindow) ? \"Child \" : \"\", (flags & ImGuiWindowFlags_Tooltip) ? \"Tooltip \" : \"\", (flags & ImGuiWindowFlags_Popup) ? \"Popup \" : \"\",\n\t\t(flags & ImGuiWindowFlags_Modal) ? \"Modal \" : \"\", (flags & ImGuiWindowFlags_ChildMenu) ? \"ChildMenu \" : \"\", (flags & ImGuiWindowFlags_NoSavedSettings) ? \"NoSavedSettings \" : \"\",\n\t\t(flags & ImGuiWindowFlags_NoMouseInputs) ? \"NoMouseInputs\" : \"\", (flags & ImGuiWindowFlags_NoNavInputs) ? \"NoNavInputs\" : \"\", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? \"AlwaysAutoResize\" : \"\");\n\tBulletText(\"Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s\", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? \"X\" : \"\", window->ScrollbarY ? \"Y\" : \"\");\n\tBulletText(\"Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d\", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);\n\tBulletText(\"Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d\", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);\n\tfor (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)\n\t{\n\t\tImRect r = window->NavRectRel[layer];\n\t\tif (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)\n\t\t\tBulletText(\"NavLastIds[%d]: 0x%08X\", layer, window->NavLastIds[layer]);\n\t\telse\n\t\t\tBulletText(\"NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)\", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);\n\t\tDebugLocateItemOnHover(window->NavLastIds[layer]);\n\t}\n\tconst ImVec2* pr = window->NavPreferredScoringPosRel;\n\tfor (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)\n\t\tBulletText(\"NavPreferredScoringPosRel[%d] = {%.1f,%.1f)\", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater.\n\tBulletText(\"NavLayersActiveMask: %X, NavLastChildNavWindow: %s\", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : \"NULL\");\n\tif (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, \"RootWindow\"); }\n\tif (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, \"ParentWindow\"); }\n\tif (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, \"ChildWindows\"); }\n\tif (window->ColumnsStorage.Size > 0 && TreeNode(\"Columns\", \"Columns sets (%d)\", window->ColumnsStorage.Size))\n\t{\n\t\tfor (ImGuiOldColumns& columns : window->ColumnsStorage)\n\t\t\tDebugNodeColumns(&columns);\n\t\tTreePop();\n\t}\n\tDebugNodeStorage(&window->StateStorage, \"Storage\");\n\tTreePop();\n}\n\nvoid ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings)\n{\n\tif (settings->WantDelete)\n\t\tBeginDisabled();\n\tText(\"0x%08X \\\"%s\\\" Pos (%d,%d) Size (%d,%d) Collapsed=%d\",\n\t\tsettings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);\n\tif (settings->WantDelete)\n\t\tEndDisabled();\n}\n\nvoid ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label)\n{\n\tif (!TreeNode(label, \"%s (%d)\", label, windows->Size))\n\t\treturn;\n\tfor (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back\n\t{\n\t\tPushID((*windows)[i]);\n\t\tDebugNodeWindow((*windows)[i], \"Window\");\n\t\tPopID();\n\t}\n\tTreePop();\n}\n\n// FIXME-OPT: This is technically suboptimal, but it is simpler this way.\nvoid ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack)\n{\n\tfor (int i = 0; i < windows_size; i++)\n\t{\n\t\tImGuiWindow* window = windows[i];\n\t\tif (window->ParentWindowInBeginStack != parent_in_begin_stack)\n\t\t\tcontinue;\n\t\tchar buf[20];\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"[%04d] Window\", window->BeginOrderWithinContext);\n\t\t//BulletText(\"[%04d] Window '%s'\", window->BeginOrderWithinContext, window->Name);\n\t\tDebugNodeWindow(window, buf);\n\t\tIndent();\n\t\tDebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window);\n\t\tUnindent();\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] DEBUG LOG WINDOW\n//-----------------------------------------------------------------------------\n\nvoid ImGui::DebugLog(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tDebugLogV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::DebugLogV(const char* fmt, va_list args)\n{\n\tImGuiContext& g = *GImGui;\n\tconst int old_size = g.DebugLogBuf.size();\n\tg.DebugLogBuf.appendf(\"[%05d] \", g.FrameCount);\n\tg.DebugLogBuf.appendfv(fmt, args);\n\tif (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY)\n\t\tIMGUI_DEBUG_PRINTF(\"%s\", g.DebugLogBuf.begin() + old_size);\n\tg.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size());\n}\n\nvoid ImGui::ShowDebugLogWindow(bool* p_open)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))\n\t\tSetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver);\n\tif (!Begin(\"Dear ImGui Debug Log\", p_open) || GetCurrentWindow()->BeginCount > 1)\n\t{\n\t\tEnd();\n\t\treturn;\n\t}\n\n\tCheckboxFlags(\"All\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_);\n\tSameLine(); CheckboxFlags(\"ActiveId\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId);\n\tSameLine(); CheckboxFlags(\"Focus\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus);\n\tSameLine(); CheckboxFlags(\"Popup\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup);\n\tSameLine(); CheckboxFlags(\"Nav\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav);\n\tSameLine(); if (CheckboxFlags(\"Clipper\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip(\"Clipper log auto-disabled after 2 frames\");\n\t//SameLine(); CheckboxFlags(\"Selection\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventSelection);\n\tSameLine(); CheckboxFlags(\"IO\", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO);\n\n\tif (SmallButton(\"Clear\"))\n\t{\n\t\tg.DebugLogBuf.clear();\n\t\tg.DebugLogIndex.clear();\n\t}\n\tSameLine();\n\tif (SmallButton(\"Copy\"))\n\t\tSetClipboardText(g.DebugLogBuf.c_str());\n\tBeginChild(\"##log\", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);\n\n\tImGuiListClipper clipper;\n\tclipper.Begin(g.DebugLogIndex.size());\n\twhile (clipper.Step())\n\t\tfor (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)\n\t\t{\n\t\t\tconst char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no);\n\t\t\tconst char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no);\n\t\t\tTextUnformatted(line_begin, line_end);\n\t\t\tImRect text_rect = g.LastItemData.Rect;\n\t\t\tif (IsItemHovered())\n\t\t\t\tfor (const char* p = line_begin; p <= line_end - 10; p++)\n\t\t\t\t{\n\t\t\t\t\tImGuiID id = 0;\n\t\t\t\t\tif (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, \"%X\", &id) != 1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tImVec2 p0 = CalcTextSize(line_begin, p);\n\t\t\t\t\tImVec2 p1 = CalcTextSize(p, p + 10);\n\t\t\t\t\tg.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));\n\t\t\t\t\tif (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true))\n\t\t\t\t\t\tDebugLocateItemOnHover(id);\n\t\t\t\t\tp += 10;\n\t\t\t\t}\n\t\t}\n\tif (GetScrollY() >= GetScrollMaxY())\n\t\tSetScrollHereY(1.0f);\n\tEndChild();\n\n\tEnd();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)\n//-----------------------------------------------------------------------------\n\n// Draw a small cross at current CursorPos in current window's DrawList\nvoid ImGui::DebugDrawCursorPos(ImU32 col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImVec2 pos = window->DC.CursorPos;\n\twindow->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f);\n\twindow->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f);\n}\n\n// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList\nvoid ImGui::DebugDrawLineExtents(ImU32 col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tfloat curr_x = window->DC.CursorPos.x;\n\tfloat line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y);\n\tfloat line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y);\n\twindow->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f);\n\twindow->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f);\n\twindow->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f);\n}\n\n// Draw last item rect in ForegroundDrawList (so it is always visible)\nvoid ImGui::DebugDrawItemRect(ImU32 col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tGetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col);\n}\n\n// [DEBUG] Locate item position/rectangle given an ID.\nstatic const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255);  // Green\n\nvoid ImGui::DebugLocateItem(ImGuiID target_id)\n{\n\tImGuiContext& g = *GImGui;\n\tg.DebugLocateId = target_id;\n\tg.DebugLocateFrames = 2;\n}\n\nvoid ImGui::DebugLocateItemOnHover(ImGuiID target_id)\n{\n\tif (target_id == 0 || !IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenBlockedByPopup))\n\t\treturn;\n\tImGuiContext& g = *GImGui;\n\tDebugLocateItem(target_id);\n\tGetForegroundDrawList(g.CurrentWindow)->AddRect(g.LastItemData.Rect.Min - ImVec2(3.0f, 3.0f), g.LastItemData.Rect.Max + ImVec2(3.0f, 3.0f), DEBUG_LOCATE_ITEM_COLOR);\n}\n\nvoid ImGui::DebugLocateItemResolveWithLastItem()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiLastItemData item_data = g.LastItemData;\n\tg.DebugLocateId = 0;\n\tImDrawList* draw_list = GetForegroundDrawList(g.CurrentWindow);\n\tImRect r = item_data.Rect;\n\tr.Expand(3.0f);\n\tImVec2 p1 = g.IO.MousePos;\n\tImVec2 p2 = ImVec2((p1.x < r.Min.x) ? r.Min.x : (p1.x > r.Max.x) ? r.Max.x : p1.x, (p1.y < r.Min.y) ? r.Min.y : (p1.y > r.Max.y) ? r.Max.y : p1.y);\n\tdraw_list->AddRect(r.Min, r.Max, DEBUG_LOCATE_ITEM_COLOR);\n\tdraw_list->AddLine(p1, p2, DEBUG_LOCATE_ITEM_COLOR);\n}\n\n// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.\nvoid ImGui::UpdateDebugToolItemPicker()\n{\n\tImGuiContext& g = *GImGui;\n\tg.DebugItemPickerBreakId = 0;\n\tif (!g.DebugItemPickerActive)\n\t\treturn;\n\n\tconst ImGuiID hovered_id = g.HoveredIdPreviousFrame;\n\tSetMouseCursor(ImGuiMouseCursor_Hand);\n\tif (IsKeyPressed(ImGuiKey_Escape))\n\t\tg.DebugItemPickerActive = false;\n\tconst bool change_mapping = g.IO.KeyMods == (ImGuiMod_Ctrl | ImGuiMod_Shift);\n\tif (!change_mapping && IsMouseClicked(g.DebugItemPickerMouseButton) && hovered_id)\n\t{\n\t\tg.DebugItemPickerBreakId = hovered_id;\n\t\tg.DebugItemPickerActive = false;\n\t}\n\tfor (int mouse_button = 0; mouse_button < 3; mouse_button++)\n\t\tif (change_mapping && IsMouseClicked(mouse_button))\n\t\t\tg.DebugItemPickerMouseButton = (ImU8)mouse_button;\n\tSetNextWindowBgAlpha(0.70f);\n\tif (!BeginTooltip())\n\t\treturn;\n\tText(\"HoveredId: 0x%08X\", hovered_id);\n\tText(\"Press ESC to abort picking.\");\n\tconst char* mouse_button_names[] = { \"Left\", \"Right\", \"Middle\" };\n\tif (change_mapping)\n\t\tText(\"Remap w/ Ctrl+Shift: click anywhere to select new mouse button.\");\n\telse\n\t\tTextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), \"Click %s Button to break in debugger! (remap w/ Ctrl+Shift)\", mouse_button_names[g.DebugItemPickerMouseButton]);\n\tEndTooltip();\n}\n\n// [DEBUG] Stack Tool: update queries. Called by NewFrame()\nvoid ImGui::UpdateDebugToolStackQueries()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiStackTool* tool = &g.DebugStackTool;\n\n\t// Clear hook when stack tool is not visible\n\tg.DebugHookIdInfo = 0;\n\tif (g.FrameCount != tool->LastActiveFrame + 1)\n\t\treturn;\n\n\t// Update queries. The steps are: -1: query Stack, >= 0: query each stack item\n\t// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time\n\tconst ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId;\n\tif (tool->QueryId != query_id)\n\t{\n\t\ttool->QueryId = query_id;\n\t\ttool->StackLevel = -1;\n\t\ttool->Results.resize(0);\n\t}\n\tif (query_id == 0)\n\t\treturn;\n\n\t// Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)\n\tint stack_level = tool->StackLevel;\n\tif (stack_level >= 0 && stack_level < tool->Results.Size)\n\t\tif (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2)\n\t\t\ttool->StackLevel++;\n\n\t// Update hook\n\tstack_level = tool->StackLevel;\n\tif (stack_level == -1)\n\t\tg.DebugHookIdInfo = query_id;\n\tif (stack_level >= 0 && stack_level < tool->Results.Size)\n\t{\n\t\tg.DebugHookIdInfo = tool->Results[stack_level].ID;\n\t\ttool->Results[stack_level].QueryFrameCount++;\n\t}\n}\n\n// [DEBUG] Stack tool: hooks called by GetID() family functions\nvoid ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiStackTool* tool = &g.DebugStackTool;\n\n\t// Step 0: stack query\n\t// This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget.\n\tif (tool->StackLevel == -1)\n\t{\n\t\ttool->StackLevel++;\n\t\ttool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());\n\t\tfor (int n = 0; n < window->IDStack.Size + 1; n++)\n\t\t\ttool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id;\n\t\treturn;\n\t}\n\n\t// Step 1+: query for individual level\n\tIM_ASSERT(tool->StackLevel >= 0);\n\tif (tool->StackLevel != window->IDStack.Size)\n\t\treturn;\n\tImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];\n\tIM_ASSERT(info->ID == id && info->QueryFrameCount > 0);\n\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S32:\n\t\tImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), \"%d\", (int)(intptr_t)data_id);\n\t\tbreak;\n\tcase ImGuiDataType_String:\n\t\tImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), \"%.*s\", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id);\n\t\tbreak;\n\tcase ImGuiDataType_Pointer:\n\t\tImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), \"(void*)0x%p\", data_id);\n\t\tbreak;\n\tcase ImGuiDataType_ID:\n\t\tif (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.\n\t\t\treturn;\n\t\tImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), \"0x%08X [override]\", id);\n\t\tbreak;\n\tdefault:\n\t\tIM_ASSERT(0);\n\t}\n\tinfo->QuerySuccess = true;\n\tinfo->DataType = data_type;\n}\n\nstatic int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size)\n{\n\tImGuiStackLevelInfo* info = &tool->Results[n];\n\tImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;\n\tif (window)                                                                 // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)\n\t\treturn ImFormatString(buf, buf_size, format_for_ui ? \"\\\"%s\\\" [window]\" : \"%s\", window->Name);\n\tif (info->QuerySuccess)                                                     // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button(\"\") where they both have same id)\n\t\treturn ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? \"\\\"%s\\\"\" : \"%s\", info->Desc);\n\tif (tool->StackLevel < tool->Results.Size)                                  // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.\n\t\treturn (*buf = 0);\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\tif (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID))   // Source: ImGuiTestEngine's ItemInfo()\n\t\treturn ImFormatString(buf, buf_size, format_for_ui ? \"??? \\\"%s\\\"\" : \"%s\", label);\n#endif\n\treturn ImFormatString(buf, buf_size, \"???\");\n}\n\n// Stack Tool: Display UI\nvoid ImGui::ShowStackToolWindow(bool* p_open)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))\n\t\tSetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver);\n\tif (!Begin(\"Dear ImGui Stack Tool\", p_open) || GetCurrentWindow()->BeginCount > 1)\n\t{\n\t\tEnd();\n\t\treturn;\n\t}\n\n\t// Display hovered/active status\n\tImGuiStackTool* tool = &g.DebugStackTool;\n\tconst ImGuiID hovered_id = g.HoveredIdPreviousFrame;\n\tconst ImGuiID active_id = g.ActiveId;\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\tText(\"HoveredId: 0x%08X (\\\"%s\\\"), ActiveId:  0x%08X (\\\"%s\\\")\", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : \"\", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : \"\");\n#else\n\tText(\"HoveredId: 0x%08X, ActiveId:  0x%08X\", hovered_id, active_id);\n#endif\n\tSameLine();\n\tMetricsHelpMarker(\"Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\\nEach level of the stack correspond to a PushID() call.\\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\\nRead FAQ entry about the ID stack for details.\");\n\n\t// CTRL+C to copy path\n\tconst float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime;\n\tCheckbox(\"Ctrl+C: copy path to clipboard\", &tool->CopyToClipboardOnCtrlC);\n\tSameLine();\n\tTextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), \"*COPIED*\");\n\tif (tool->CopyToClipboardOnCtrlC && IsKeyDown(ImGuiMod_Ctrl) && IsKeyPressed(ImGuiKey_C))\n\t{\n\t\ttool->CopyToClipboardLastTime = (float)g.Time;\n\t\tchar* p = g.TempBuffer.Data;\n\t\tchar* p_end = p + g.TempBuffer.Size;\n\t\tfor (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++)\n\t\t{\n\t\t\t*p++ = '/';\n\t\t\tchar level_desc[256];\n\t\t\tStackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc));\n\t\t\tfor (int n = 0; level_desc[n] && p + 2 < p_end; n++)\n\t\t\t{\n\t\t\t\tif (level_desc[n] == '/')\n\t\t\t\t\t*p++ = '\\\\';\n\t\t\t\t*p++ = level_desc[n];\n\t\t\t}\n\t\t}\n\t\t*p = '\\0';\n\t\tSetClipboardText(g.TempBuffer.Data);\n\t}\n\n\t// Display decorated stack\n\ttool->LastActiveFrame = g.FrameCount;\n\tif (tool->Results.Size > 0 && BeginTable(\"##table\", 3, ImGuiTableFlags_Borders))\n\t{\n\t\tconst float id_width = CalcTextSize(\"0xDDDDDDDD\").x;\n\t\tTableSetupColumn(\"Seed\", ImGuiTableColumnFlags_WidthFixed, id_width);\n\t\tTableSetupColumn(\"PushID\", ImGuiTableColumnFlags_WidthStretch);\n\t\tTableSetupColumn(\"Result\", ImGuiTableColumnFlags_WidthFixed, id_width);\n\t\tTableHeadersRow();\n\t\tfor (int n = 0; n < tool->Results.Size; n++)\n\t\t{\n\t\t\tImGuiStackLevelInfo* info = &tool->Results[n];\n\t\t\tTableNextColumn();\n\t\t\tText(\"0x%08X\", (n > 0) ? tool->Results[n - 1].ID : 0);\n\t\t\tTableNextColumn();\n\t\t\tStackToolFormatLevelInfo(tool, n, true, g.TempBuffer.Data, g.TempBuffer.Size);\n\t\t\tTextUnformatted(g.TempBuffer.Data);\n\t\t\tTableNextColumn();\n\t\t\tText(\"0x%08X\", info->ID);\n\t\t\tif (n == tool->Results.Size - 1)\n\t\t\t\tTableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header));\n\t\t}\n\t\tEndTable();\n\t}\n\tEnd();\n}\n\n#else\n\nvoid ImGui::ShowMetricsWindow(bool*) {}\nvoid ImGui::ShowFontAtlas(ImFontAtlas*) {}\nvoid ImGui::DebugNodeColumns(ImGuiOldColumns*) {}\nvoid ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {}\nvoid ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}\nvoid ImGui::DebugNodeFont(ImFont*) {}\nvoid ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}\nvoid ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}\nvoid ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}\nvoid ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}\nvoid ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}\nvoid ImGui::DebugNodeViewport(ImGuiViewportP*) {}\n\nvoid ImGui::DebugLog(const char*, ...) {}\nvoid ImGui::DebugLogV(const char*, va_list) {}\nvoid ImGui::ShowDebugLogWindow(bool*) {}\nvoid ImGui::ShowStackToolWindow(bool*) {}\nvoid ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}\nvoid ImGui::UpdateDebugToolItemPicker() {}\nvoid ImGui::UpdateDebugToolStackQueries() {}\n\n#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\n//-----------------------------------------------------------------------------\n\n// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.\n// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.\n#ifdef IMGUI_INCLUDE_IMGUI_USER_INL\n#include \"imgui_user.inl\"\n#endif\n\n//-----------------------------------------------------------------------------\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imgui.h",
    "content": "// dear imgui, v1.89.9\n// (headers)\n\n// Help:\n// - Read FAQ at http://dearimgui.com/faq\n// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.\n// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.\n// Read imgui.cpp for details, links and comments.\n\n// Resources:\n// - FAQ                   http://dearimgui.com/faq\n// - Homepage              https://github.com/ocornut/imgui\n// - Releases & changelog  https://github.com/ocornut/imgui/releases\n// - Gallery               https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!)\n// - Wiki                  https://github.com/ocornut/imgui/wiki (lots of good stuff there)\n// - Getting Started       https://github.com/ocornut/imgui/wiki/Getting-Started\n// - Glossary              https://github.com/ocornut/imgui/wiki/Glossary\n// - Issues & support      https://github.com/ocornut/imgui/issues\n// - Tests & Automation    https://github.com/ocornut/imgui_test_engine\n\n// Getting Started?\n// - Read https://github.com/ocornut/imgui/wiki/Getting-Started\n// - For first-time users having issues compiling/linking/running/loading fonts:\n//   please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.\n\n// Library Version\n// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')\n#define IMGUI_VERSION       \"1.89.9\"\n#define IMGUI_VERSION_NUM   18990\n#define IMGUI_HAS_TABLE\n\n/*\n\nIndex of this file:\n// [SECTION] Header mess\n// [SECTION] Forward declarations and basic types\n// [SECTION] Dear ImGui end-user API functions\n// [SECTION] Flags & Enumerations\n// [SECTION] Helpers: Memory allocations macros, ImVector<>\n// [SECTION] ImGuiStyle\n// [SECTION] ImGuiIO\n// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs)\n// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)\n// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)\n// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)\n// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)\n// [SECTION] Platform Dependent Interfaces (ImGuiPlatformImeData)\n// [SECTION] Obsolete functions and types\n\n*/\n\n#pragma once\n\n// Configuration file with compile-time options\n// (edit imconfig.h or '#define IMGUI_USER_CONFIG \"myfilename.h\" from your build system')\n#ifdef IMGUI_USER_CONFIG\n#include IMGUI_USER_CONFIG\n#endif\n#include \"imconfig.h\"\n\n#ifndef IMGUI_DISABLE\n\n//-----------------------------------------------------------------------------\n// [SECTION] Header mess\n//-----------------------------------------------------------------------------\n\n// Includes\n#include <float.h>                  // FLT_MIN, FLT_MAX\n#include <stdarg.h>                 // va_list, va_start, va_end\n#include <stddef.h>                 // ptrdiff_t, NULL\n#include <string.h>                 // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp\n\n// Define attributes of all API symbols declarations (e.g. for DLL under Windows)\n// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h)\n// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API)\n#ifndef IMGUI_API\n#define IMGUI_API\n#endif\n#ifndef IMGUI_IMPL_API\n#define IMGUI_IMPL_API              IMGUI_API\n#endif\n\n// Helper Macros\n#ifndef IM_ASSERT\n#include <assert.h>\n#define IM_ASSERT(_EXPR)            assert(_EXPR)                               // You can override the default assert handler by editing imconfig.h\n#endif\n#define IM_ARRAYSIZE(_ARR)          ((int)(sizeof(_ARR) / sizeof(*(_ARR))))     // Size of a static C-style array. Don't use on pointers!\n#define IM_UNUSED(_VAR)             ((void)(_VAR))                              // Used to silence \"unused variable warnings\". Often useful as asserts may be stripped out from final builds.\n#define IM_OFFSETOF(_TYPE,_MEMBER)  offsetof(_TYPE, _MEMBER)                    // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11\n#define IMGUI_CHECKVERSION()        ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))\n\n// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions.\n#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__)\n#define IM_FMTARGS(FMT)             __attribute__((format(gnu_printf, FMT, FMT+1)))\n#define IM_FMTLIST(FMT)             __attribute__((format(gnu_printf, FMT, 0)))\n#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__))\n#define IM_FMTARGS(FMT)             __attribute__((format(printf, FMT, FMT+1)))\n#define IM_FMTLIST(FMT)             __attribute__((format(printf, FMT, 0)))\n#else\n#define IM_FMTARGS(FMT)\n#define IM_FMTLIST(FMT)\n#endif\n\n// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions)\n#if defined(_MSC_VER) && !defined(__clang__)  && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID)\n#define IM_MSVC_RUNTIME_CHECKS_OFF      __pragma(runtime_checks(\"\",off))     __pragma(check_stack(off)) __pragma(strict_gs_check(push,off))\n#define IM_MSVC_RUNTIME_CHECKS_RESTORE  __pragma(runtime_checks(\"\",restore)) __pragma(check_stack())    __pragma(strict_gs_check(pop))\n#else\n#define IM_MSVC_RUNTIME_CHECKS_OFF\n#define IM_MSVC_RUNTIME_CHECKS_RESTORE\n#endif\n\n// Warnings\n#ifdef _MSC_VER\n#pragma warning (push)\n#pragma warning (disable: 26495)    // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).\n#endif\n#if defined(__clang__)\n#pragma clang diagnostic push\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wold-style-cast\"\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"\n#pragma clang diagnostic ignored \"-Wreserved-identifier\"            // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter\n#elif defined(__GNUC__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wpragmas\"          // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"  // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#endif\n\n//-----------------------------------------------------------------------------\n// [SECTION] Forward declarations and basic types\n//-----------------------------------------------------------------------------\n\n// Forward declarations\nstruct ImDrawChannel;               // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit()\nstruct ImDrawCmd;                   // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)\nstruct ImDrawData;                  // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix.\nstruct ImDrawList;                  // A single draw command list (generally one per window, conceptually you may see this as a dynamic \"mesh\" builder)\nstruct ImDrawListSharedData;        // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself)\nstruct ImDrawListSplitter;          // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back.\nstruct ImDrawVert;                  // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)\nstruct ImFont;                      // Runtime data for a single font within a parent ImFontAtlas\nstruct ImFontAtlas;                 // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader\nstruct ImFontBuilderIO;             // Opaque interface to a font builder (stb_truetype or FreeType).\nstruct ImFontConfig;                // Configuration data when adding a font or merging fonts\nstruct ImFontGlyph;                 // A single font glyph (code point + coordinates within in ImFontAtlas + offset)\nstruct ImFontGlyphRangesBuilder;    // Helper to build glyph ranges from text/string data\nstruct ImColor;                     // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using)\nstruct ImGuiContext;                // Dear ImGui context (opaque structure, unless including imgui_internal.h)\nstruct ImGuiIO;                     // Main configuration and I/O between your application and ImGui\nstruct ImGuiInputTextCallbackData;  // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use)\nstruct ImGuiKeyData;                // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions.\nstruct ImGuiListClipper;            // Helper to manually clip large list of items\nstruct ImGuiOnceUponAFrame;         // Helper for running a block of code not more than once a frame\nstruct ImGuiPayload;                // User data payload for drag and drop operations\nstruct ImGuiPlatformImeData;        // Platform IME data for io.SetPlatformImeDataFn() function.\nstruct ImGuiSizeCallbackData;       // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)\nstruct ImGuiStorage;                // Helper for key->value storage\nstruct ImGuiStyle;                  // Runtime data for styling/colors\nstruct ImGuiTableSortSpecs;         // Sorting specifications for a table (often handling sort specs for a single column, occasionally more)\nstruct ImGuiTableColumnSortSpecs;   // Sorting specification for one column of a table\nstruct ImGuiTextBuffer;             // Helper to hold and append into a text buffer (~string builder)\nstruct ImGuiTextFilter;             // Helper to parse and apply text filters (e.g. \"aaaaa[,bbbbb][,ccccc]\")\nstruct ImGuiViewport;               // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor\n\n// Enumerations\n// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration)\n// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!\n//   In Visual Studio IDE: CTRL+comma (\"Edit.GoToAll\") can follow symbols in comments, whereas CTRL+F12 (\"Edit.GoToImplementation\") cannot.\n//   With Visual Assist installed: ALT+G (\"VAssistX.GoToImplementation\") can also follow symbols in comments.\nenum ImGuiKey : int;                // -> enum ImGuiKey              // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value)\nenum ImGuiMouseSource : int;        // -> enum ImGuiMouseSource      // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen)\ntypedef int ImGuiCol;               // -> enum ImGuiCol_             // Enum: A color identifier for styling\ntypedef int ImGuiCond;              // -> enum ImGuiCond_            // Enum: A condition for many Set*() functions\ntypedef int ImGuiDataType;          // -> enum ImGuiDataType_        // Enum: A primary data type\ntypedef int ImGuiDir;               // -> enum ImGuiDir_             // Enum: A cardinal direction\ntypedef int ImGuiMouseButton;       // -> enum ImGuiMouseButton_     // Enum: A mouse button identifier (0=left, 1=right, 2=middle)\ntypedef int ImGuiMouseCursor;       // -> enum ImGuiMouseCursor_     // Enum: A mouse cursor shape\ntypedef int ImGuiSortDirection;     // -> enum ImGuiSortDirection_   // Enum: A sorting direction (ascending or descending)\ntypedef int ImGuiStyleVar;          // -> enum ImGuiStyleVar_        // Enum: A variable identifier for styling\ntypedef int ImGuiTableBgTarget;     // -> enum ImGuiTableBgTarget_   // Enum: A color target for TableSetBgColor()\n\n// Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file)\n// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!\n//   In Visual Studio IDE: CTRL+comma (\"Edit.GoToAll\") can follow symbols in comments, whereas CTRL+F12 (\"Edit.GoToImplementation\") cannot.\n//   With Visual Assist installed: ALT+G (\"VAssistX.GoToImplementation\") can also follow symbols in comments.\ntypedef int ImDrawFlags;            // -> enum ImDrawFlags_          // Flags: for ImDrawList functions\ntypedef int ImDrawListFlags;        // -> enum ImDrawListFlags_      // Flags: for ImDrawList instance\ntypedef int ImFontAtlasFlags;       // -> enum ImFontAtlasFlags_     // Flags: for ImFontAtlas build\ntypedef int ImGuiBackendFlags;      // -> enum ImGuiBackendFlags_    // Flags: for io.BackendFlags\ntypedef int ImGuiButtonFlags;       // -> enum ImGuiButtonFlags_     // Flags: for InvisibleButton()\ntypedef int ImGuiColorEditFlags;    // -> enum ImGuiColorEditFlags_  // Flags: for ColorEdit4(), ColorPicker4() etc.\ntypedef int ImGuiConfigFlags;       // -> enum ImGuiConfigFlags_     // Flags: for io.ConfigFlags\ntypedef int ImGuiComboFlags;        // -> enum ImGuiComboFlags_      // Flags: for BeginCombo()\ntypedef int ImGuiDragDropFlags;     // -> enum ImGuiDragDropFlags_   // Flags: for BeginDragDropSource(), AcceptDragDropPayload()\ntypedef int ImGuiFocusedFlags;      // -> enum ImGuiFocusedFlags_    // Flags: for IsWindowFocused()\ntypedef int ImGuiHoveredFlags;      // -> enum ImGuiHoveredFlags_    // Flags: for IsItemHovered(), IsWindowHovered() etc.\ntypedef int ImGuiInputTextFlags;    // -> enum ImGuiInputTextFlags_  // Flags: for InputText(), InputTextMultiline()\ntypedef int ImGuiKeyChord;          // -> ImGuiKey | ImGuiMod_XXX    // Flags: for storage only for now: an ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values.\ntypedef int ImGuiPopupFlags;        // -> enum ImGuiPopupFlags_      // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen()\ntypedef int ImGuiSelectableFlags;   // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()\ntypedef int ImGuiSliderFlags;       // -> enum ImGuiSliderFlags_     // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.\ntypedef int ImGuiTabBarFlags;       // -> enum ImGuiTabBarFlags_     // Flags: for BeginTabBar()\ntypedef int ImGuiTabItemFlags;      // -> enum ImGuiTabItemFlags_    // Flags: for BeginTabItem()\ntypedef int ImGuiTableFlags;        // -> enum ImGuiTableFlags_      // Flags: For BeginTable()\ntypedef int ImGuiTableColumnFlags;  // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn()\ntypedef int ImGuiTableRowFlags;     // -> enum ImGuiTableRowFlags_   // Flags: For TableNextRow()\ntypedef int ImGuiTreeNodeFlags;     // -> enum ImGuiTreeNodeFlags_   // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader()\ntypedef int ImGuiViewportFlags;     // -> enum ImGuiViewportFlags_   // Flags: for ImGuiViewport\ntypedef int ImGuiWindowFlags;       // -> enum ImGuiWindowFlags_     // Flags: for Begin(), BeginChild()\n\n// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]\n// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.\n// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.\n#ifndef ImTextureID\ntypedef void* ImTextureID;          // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)\n#endif\n\n// ImDrawIdx: vertex index. [Compile-time configurable type]\n// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).\n// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.\n#ifndef ImDrawIdx\ntypedef unsigned short ImDrawIdx;   // Default: 16-bit (for maximum compatibility with renderer backends)\n#endif\n\n// Scalar data types\ntypedef unsigned int        ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string)\ntypedef signed char         ImS8;   // 8-bit signed integer\ntypedef unsigned char       ImU8;   // 8-bit unsigned integer\ntypedef signed short        ImS16;  // 16-bit signed integer\ntypedef unsigned short      ImU16;  // 16-bit unsigned integer\ntypedef signed int          ImS32;  // 32-bit signed integer == int\ntypedef unsigned int        ImU32;  // 32-bit unsigned integer (often used to store packed colors)\ntypedef signed   long long  ImS64;  // 64-bit signed integer\ntypedef unsigned long long  ImU64;  // 64-bit unsigned integer\n\n// Character types\n// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)\ntypedef unsigned short ImWchar16;   // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.\ntypedef unsigned int ImWchar32;     // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.\n#ifdef IMGUI_USE_WCHAR32            // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16]\ntypedef ImWchar32 ImWchar;\n#else\ntypedef ImWchar16 ImWchar;\n#endif\n\n// Callback and functions types\ntypedef int     (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data);    // Callback function for ImGui::InputText()\ntypedef void    (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);              // Callback function for ImGui::SetNextWindowSizeConstraints()\ntypedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data);               // Function signature for ImGui::SetAllocatorFunctions()\ntypedef void    (*ImGuiMemFreeFunc)(void* ptr, void* user_data);                // Function signature for ImGui::SetAllocatorFunctions()\n\n// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type]\n// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type.\nIM_MSVC_RUNTIME_CHECKS_OFF\nstruct ImVec2\n{\n\tfloat                                   x, y;\n\tconstexpr ImVec2() : x(0.0f), y(0.0f) { }\n\tconstexpr ImVec2(float _x, float _y) : x(_x), y(_y) { }\n\tfloat& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine.\n\tfloat  operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; }\n#ifdef IM_VEC2_CLASS_EXTRA\n\tIM_VEC2_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.\n#endif\n};\n\n// ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type]\nstruct ImVec4\n{\n\tfloat                                                     x, y, z, w;\n\tconstexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { }\n\tconstexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { }\n#ifdef IM_VEC4_CLASS_EXTRA\n\tIM_VEC4_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4.\n#endif\n};\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n//-----------------------------------------------------------------------------\n// [SECTION] Dear ImGui end-user API functions\n// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)\n//-----------------------------------------------------------------------------\n\nnamespace ImGui\n{\n\t// Context creation and access\n\t// - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts.\n\t// - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()\n\t//   for each static/DLL boundary you are calling from. Read \"Context and Memory Allocators\" section of imgui.cpp for details.\n\tIMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL);\n\tIMGUI_API void          DestroyContext(ImGuiContext* ctx = NULL);   // NULL = destroy current context\n\tIMGUI_API ImGuiContext* GetCurrentContext();\n\tIMGUI_API void          SetCurrentContext(ImGuiContext* ctx);\n\n\t// Main\n\tIMGUI_API ImGuiIO& GetIO();                                    // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags)\n\tIMGUI_API ImGuiStyle& GetStyle();                                 // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame!\n\tIMGUI_API void          NewFrame();                                 // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame().\n\tIMGUI_API void          EndFrame();                                 // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all!\n\tIMGUI_API void          Render();                                   // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData().\n\tIMGUI_API ImDrawData* GetDrawData();                              // valid after Render() and until the next call to NewFrame(). this is what you have to render.\n\n\t// Demo, Debug, Information\n\tIMGUI_API void          ShowDemoWindow(bool* p_open = NULL);        // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!\n\tIMGUI_API void          ShowMetricsWindow(bool* p_open = NULL);     // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc.\n\tIMGUI_API void          ShowDebugLogWindow(bool* p_open = NULL);    // create Debug Log window. display a simplified log of important dear imgui events.\n\tIMGUI_API void          ShowStackToolWindow(bool* p_open = NULL);   // create Stack Tool window. hover items with mouse to query information about the source of their unique ID.\n\tIMGUI_API void          ShowAboutWindow(bool* p_open = NULL);       // create About window. display Dear ImGui version, credits and build/system information.\n\tIMGUI_API void          ShowStyleEditor(ImGuiStyle* ref = NULL);    // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)\n\tIMGUI_API bool          ShowStyleSelector(const char* label);       // add style selector block (not a window), essentially a combo listing the default styles.\n\tIMGUI_API void          ShowFontSelector(const char* label);        // add font selector block (not a window), essentially a combo listing the loaded fonts.\n\tIMGUI_API void          ShowUserGuide();                            // add basic help/info block (not a window): how to manipulate ImGui as an end-user (mouse/keyboard controls).\n\tIMGUI_API const char* GetVersion();                               // get the compiled version string e.g. \"1.80 WIP\" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp)\n\n\t// Styles\n\tIMGUI_API void          StyleColorsDark(ImGuiStyle* dst = NULL);    // new, recommended style (default)\n\tIMGUI_API void          StyleColorsLight(ImGuiStyle* dst = NULL);   // best used with borders and a custom, thicker font\n\tIMGUI_API void          StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style\n\n\t// Windows\n\t// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack.\n\t// - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window,\n\t//   which clicking will set the boolean to false when clicked.\n\t// - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times.\n\t//   Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin().\n\t// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting\n\t//   anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!\n\t//   [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu,\n\t//    BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function\n\t//    returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.]\n\t// - Note that the bottom of window stack always contains a window called \"Debug\".\n\tIMGUI_API bool          Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);\n\tIMGUI_API void          End();\n\n\t// Child Windows\n\t// - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child.\n\t// - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400).\n\t// - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window.\n\t//   Always call a matching EndChild() for each BeginChild() call, regardless of its return value.\n\t//   [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu,\n\t//    BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function\n\t//    returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.]\n\tIMGUI_API bool          BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0);\n\tIMGUI_API bool          BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0);\n\tIMGUI_API void          EndChild();\n\n\t// Windows Utilities\n\t// - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into.\n\tIMGUI_API bool          IsWindowAppearing();\n\tIMGUI_API bool          IsWindowCollapsed();\n\tIMGUI_API bool          IsWindowFocused(ImGuiFocusedFlags flags = 0); // is current window focused? or its root/child, depending on flags. see flags for options.\n\tIMGUI_API bool          IsWindowHovered(ImGuiHoveredFlags flags = 0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!\n\tIMGUI_API ImDrawList* GetWindowDrawList();                        // get draw list associated to the current window, to append your own drawing primitives\n\tIMGUI_API ImVec2        GetWindowPos();                             // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetScreenCursorPos())\n\tIMGUI_API ImVec2        GetWindowSize();                            // get current window size (note: it is unlikely you need to use this. Consider using GetScreenCursorPos() and e.g. GetContentRegionAvail() instead)\n\tIMGUI_API float         GetWindowWidth();                           // get current window width (shortcut for GetWindowSize().x)\n\tIMGUI_API float         GetWindowHeight();                          // get current window height (shortcut for GetWindowSize().y)\n\n\t// Window manipulation\n\t// - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin).\n\tIMGUI_API void          SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc.\n\tIMGUI_API void          SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0);                  // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()\n\tIMGUI_API void          SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints.\n\tIMGUI_API void          SetNextWindowContentSize(const ImVec2& size);                               // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin()\n\tIMGUI_API void          SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                 // set next window collapsed state. call before Begin()\n\tIMGUI_API void          SetNextWindowFocus();                                                       // set next window to be focused / top-most. call before Begin()\n\tIMGUI_API void          SetNextWindowScroll(const ImVec2& scroll);                                  // set next window scrolling value (use < 0.0f to not affect a given axis).\n\tIMGUI_API void          SetNextWindowBgAlpha(float alpha);                                          // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground.\n\tIMGUI_API void          SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0);                        // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.\n\tIMGUI_API void          SetWindowSize(const ImVec2& size, ImGuiCond cond = 0);                      // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.\n\tIMGUI_API void          SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                     // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().\n\tIMGUI_API void          SetWindowFocus();                                                           // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus().\n\tIMGUI_API void          SetWindowFontScale(float scale);                                            // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().\n\tIMGUI_API void          SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0);      // set named window position.\n\tIMGUI_API void          SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0);    // set named window size. set axis to 0.0f to force an auto-fit on this axis.\n\tIMGUI_API void          SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0);   // set named window collapsed state\n\tIMGUI_API void          SetWindowFocus(const char* name);                                           // set named window to be focused / top-most. use NULL to remove focus.\n\n\t// Content region\n\t// - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful.\n\t// - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion)\n\tIMGUI_API ImVec2        GetContentRegionAvail();                                        // == GetContentRegionMax() - GetCursorPos()\n\tIMGUI_API ImVec2        GetContentRegionMax();                                          // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates\n\tIMGUI_API ImVec2        GetWindowContentRegionMin();                                    // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates\n\tIMGUI_API ImVec2        GetWindowContentRegionMax();                                    // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates\n\n\t// Windows Scrolling\n\t// - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin().\n\t// - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY().\n\tIMGUI_API float         GetScrollX();                                                   // get scrolling amount [0 .. GetScrollMaxX()]\n\tIMGUI_API float         GetScrollY();                                                   // get scrolling amount [0 .. GetScrollMaxY()]\n\tIMGUI_API void          SetScrollX(float scroll_x);                                     // set scrolling amount [0 .. GetScrollMaxX()]\n\tIMGUI_API void          SetScrollY(float scroll_y);                                     // set scrolling amount [0 .. GetScrollMaxY()]\n\tIMGUI_API float         GetScrollMaxX();                                                // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x\n\tIMGUI_API float         GetScrollMaxY();                                                // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y\n\tIMGUI_API void          SetScrollHereX(float center_x_ratio = 0.5f);                    // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a \"default/current item\" visible, consider using SetItemDefaultFocus() instead.\n\tIMGUI_API void          SetScrollHereY(float center_y_ratio = 0.5f);                    // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a \"default/current item\" visible, consider using SetItemDefaultFocus() instead.\n\tIMGUI_API void          SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f);  // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.\n\tIMGUI_API void          SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f);  // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.\n\n\t// Parameters stacks (shared)\n\tIMGUI_API void          PushFont(ImFont* font);                                         // use NULL as a shortcut to push default font\n\tIMGUI_API void          PopFont();\n\tIMGUI_API void          PushStyleColor(ImGuiCol idx, ImU32 col);                        // modify a style color. always use this if you modify the style after NewFrame().\n\tIMGUI_API void          PushStyleColor(ImGuiCol idx, const ImVec4& col);\n\tIMGUI_API void          PopStyleColor(int count = 1);\n\tIMGUI_API void          PushStyleVar(ImGuiStyleVar idx, float val);                     // modify a style float variable. always use this if you modify the style after NewFrame().\n\tIMGUI_API void          PushStyleVar(ImGuiStyleVar idx, const ImVec2& val);             // modify a style ImVec2 variable. always use this if you modify the style after NewFrame().\n\tIMGUI_API void          PopStyleVar(int count = 1);\n\tIMGUI_API void          PushTabStop(bool tab_stop);                                     // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets\n\tIMGUI_API void          PopTabStop();\n\tIMGUI_API void          PushButtonRepeat(bool repeat);                                  // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.\n\tIMGUI_API void          PopButtonRepeat();\n\n\t// Parameters stacks (current window)\n\tIMGUI_API void          PushItemWidth(float item_width);                                // push width of items for common large \"item+label\" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side).\n\tIMGUI_API void          PopItemWidth();\n\tIMGUI_API void          SetNextItemWidth(float item_width);                             // set width of the _next_ common large \"item+label\" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side)\n\tIMGUI_API float         CalcItemWidth();                                                // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions.\n\tIMGUI_API void          PushTextWrapPos(float wrap_local_pos_x = 0.0f);                 // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space\n\tIMGUI_API void          PopTextWrapPos();\n\n\t// Style read access\n\t// - Use the ShowStyleEditor() function to interactively see/edit the colors.\n\tIMGUI_API ImFont* GetFont();                                                      // get current font\n\tIMGUI_API float         GetFontSize();                                                  // get current font size (= height in pixels) of current font with current scale applied\n\tIMGUI_API ImVec2        GetFontTexUvWhitePixel();                                       // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API\n\tIMGUI_API ImU32         GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f);              // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList\n\tIMGUI_API ImU32         GetColorU32(const ImVec4& col);                                 // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList\n\tIMGUI_API ImU32         GetColorU32(ImU32 col);                                         // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList\n\tIMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx);                                // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in.\n\n\t// Cursor / Layout\n\t// - By \"cursor\" we mean the current output position.\n\t// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.\n\t// - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget.\n\t// - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API:\n\t//    Window-local coordinates:   SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos()\n\t//    Absolute coordinate:        GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions.\n\tIMGUI_API void          Separator();                                                    // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.\n\tIMGUI_API void          SameLine(float offset_from_start_x = 0.0f, float spacing = -1.0f);  // call between widgets or groups to layout them horizontally. X position given in window coordinates.\n\tIMGUI_API void          NewLine();                                                      // undo a SameLine() or force a new line when in a horizontal-layout context.\n\tIMGUI_API void          Spacing();                                                      // add vertical spacing.\n\tIMGUI_API void          Dummy(const ImVec2& size);                                      // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into.\n\tIMGUI_API void          Indent(float indent_w = 0.0f);                                  // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0\n\tIMGUI_API void          Unindent(float indent_w = 0.0f);                                // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0\n\tIMGUI_API void          BeginGroup();                                                   // lock horizontal starting position\n\tIMGUI_API void          EndGroup();                                                     // unlock horizontal starting position + capture the whole group bounding box into one \"item\" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)\n\tIMGUI_API ImVec2        GetCursorPos();                                                 // cursor position in window coordinates (relative to window position)\n\tIMGUI_API float         GetCursorPosX();                                                //   (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc.\n\tIMGUI_API float         GetCursorPosY();                                                //    other functions such as GetCursorScreenPos or everything in ImDrawList::\n\tIMGUI_API void          SetCursorPos(const ImVec2& local_pos);                          //    are using the main, absolute coordinate system.\n\tIMGUI_API void          SetCursorPosX(float local_x);                                   //    GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.)\n\tIMGUI_API void          SetCursorPosY(float local_y);                                   //\n\tIMGUI_API ImVec2        GetCursorStartPos();                                            // initial cursor position in window coordinates\n\tIMGUI_API ImVec2        GetCursorScreenPos();                                           // cursor position in absolute coordinates (useful to work with ImDrawList API). generally top-left == GetMainViewport()->Pos == (0,0) in single viewport mode, and bottom-right == GetMainViewport()->Pos+Size == io.DisplaySize in single-viewport mode.\n\tIMGUI_API void          SetCursorScreenPos(const ImVec2& pos);                          // cursor position in absolute coordinates\n\tIMGUI_API void          AlignTextToFramePadding();                                      // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item)\n\tIMGUI_API float         GetTextLineHeight();                                            // ~ FontSize\n\tIMGUI_API float         GetTextLineHeightWithSpacing();                                 // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text)\n\tIMGUI_API float         GetFrameHeight();                                               // ~ FontSize + style.FramePadding.y * 2\n\tIMGUI_API float         GetFrameHeightWithSpacing();                                    // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets)\n\n\t// ID stack/scopes\n\t// Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui.\n\t// - Those questions are answered and impacted by understanding of the ID stack system:\n\t//   - \"Q: Why is my widget not reacting when I click on it?\"\n\t//   - \"Q: How can I have widgets with an empty label?\"\n\t//   - \"Q: How can I have multiple widgets with the same label?\"\n\t// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely\n\t//   want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.\n\t// - You can also use the \"Label##foobar\" syntax within widget label to distinguish them from each others.\n\t// - In this header file we use the \"label\"/\"name\" terminology to denote a string that will be displayed + used as an ID,\n\t//   whereas \"str_id\" denote a string that is only used as an ID and not normally displayed.\n\tIMGUI_API void          PushID(const char* str_id);                                     // push string into the ID stack (will hash string).\n\tIMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);       // push string into the ID stack (will hash string).\n\tIMGUI_API void          PushID(const void* ptr_id);                                     // push pointer into the ID stack (will hash pointer).\n\tIMGUI_API void          PushID(int int_id);                                             // push integer into the ID stack (will hash integer).\n\tIMGUI_API void          PopID();                                                        // pop from the ID stack.\n\tIMGUI_API ImGuiID       GetID(const char* str_id);                                      // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself\n\tIMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);\n\tIMGUI_API ImGuiID       GetID(const void* ptr_id);\n\n\t// Widgets: Text\n\tIMGUI_API void          TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text(\"%s\", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.\n\tIMGUI_API void          Text(const char* fmt, ...)                                      IM_FMTARGS(1); // formatted text\n\tIMGUI_API void          TextV(const char* fmt, va_list args)                            IM_FMTLIST(1);\n\tIMGUI_API void          TextColored(const ImVec4& col, const char* fmt, ...)            IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();\n\tIMGUI_API void          TextColoredV(const ImVec4& col, const char* fmt, va_list args)  IM_FMTLIST(2);\n\tIMGUI_API void          TextDisabled(const char* fmt, ...)                              IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor();\n\tIMGUI_API void          TextDisabledV(const char* fmt, va_list args)                    IM_FMTLIST(1);\n\tIMGUI_API void          TextWrapped(const char* fmt, ...)                               IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize().\n\tIMGUI_API void          TextWrappedV(const char* fmt, va_list args)                     IM_FMTLIST(1);\n\tIMGUI_API void          LabelText(const char* label, const char* fmt, ...)              IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets\n\tIMGUI_API void          LabelTextV(const char* label, const char* fmt, va_list args)    IM_FMTLIST(2);\n\tIMGUI_API void          BulletText(const char* fmt, ...)                                IM_FMTARGS(1); // shortcut for Bullet()+Text()\n\tIMGUI_API void          BulletTextV(const char* fmt, va_list args)                      IM_FMTLIST(1);\n\tIMGUI_API void          SeparatorText(const char* label);                               // currently: formatted text with an horizontal line\n\n\t// Widgets: Main\n\t// - Most widgets return true when the value has been changed or when pressed/selected\n\t// - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state.\n\tIMGUI_API bool          Button(const char* label, const ImVec2& size = ImVec2(0, 0));   // button\n\tIMGUI_API bool          SmallButton(const char* label);                                 // button with FramePadding=(0,0) to easily embed within text\n\tIMGUI_API bool          InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)\n\tIMGUI_API bool          ArrowButton(const char* str_id, ImGuiDir dir);                  // square button with an arrow shape\n\tIMGUI_API bool          Checkbox(const char* label, bool* v);\n\tIMGUI_API bool          CheckboxFlags(const char* label, int* flags, int flags_value);\n\tIMGUI_API bool          CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);\n\tIMGUI_API bool          RadioButton(const char* label, bool active);                    // use with e.g. if (RadioButton(\"one\", my_value==1)) { my_value = 1; }\n\tIMGUI_API bool          RadioButton(const char* label, int* v, int v_button);           // shortcut to handle the above pattern when value is an integer\n\tIMGUI_API void          ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL);\n\tIMGUI_API void          Bullet();                                                       // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses\n\n\t// Widgets: Images\n\t// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples\n\tIMGUI_API void          Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0));\n\tIMGUI_API bool          ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));\n\n\t// Widgets: Combo Box (Dropdown)\n\t// - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.\n\t// - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created.\n\tIMGUI_API bool          BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);\n\tIMGUI_API void          EndCombo(); // only call EndCombo() if BeginCombo() returns true!\n\tIMGUI_API bool          Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);\n\tIMGUI_API bool          Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1);      // Separate items with \\0 within a string, end item-list with \\0\\0. e.g. \"One\\0Two\\0Three\\0\"\n\tIMGUI_API bool          Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1);\n\n\t// Widgets: Drag Sliders\n\t// - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp.\n\t// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function argument is the same as 'float* v',\n\t//   the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x\n\t// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. \"%.3f\" -> 1.234; \"%5.2f secs\" -> 01.23 secs; \"Biscuit: %.0f\" -> Biscuit: 1; etc.\n\t// - Format string may also be set to NULL or use the default format (\"%f\" or \"%d\").\n\t// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).\n\t// - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used.\n\t// - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum.\n\t// - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them.\n\t// - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.\n\t//   If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361\n\tIMGUI_API bool          DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);     // If v_min >= v_max we have no bound\n\tIMGUI_API bool          DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = \"%.3f\", const char* format_max = NULL, ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = \"%d\", ImGuiSliderFlags flags = 0);  // If v_min >= v_max we have no bound\n\tIMGUI_API bool          DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = \"%d\", const char* format_max = NULL, ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);\n\n\t// Widgets: Regular Sliders\n\t// - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp.\n\t// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. \"%.3f\" -> 1.234; \"%5.2f secs\" -> 01.23 secs; \"Biscuit: %.0f\" -> Biscuit: 1; etc.\n\t// - Format string may also be set to NULL or use the default format (\"%f\" or \"%d\").\n\t// - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.\n\t//   If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361\n\tIMGUI_API bool          SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);     // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display.\n\tIMGUI_API bool          SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = \"%.0f deg\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = \"%.3f\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = \"%d\", ImGuiSliderFlags flags = 0);\n\tIMGUI_API bool          VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);\n\n\t// Widgets: Input with Keyboard\n\t// - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp.\n\t// - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc.\n\tIMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);\n\tIMGUI_API bool          InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);\n\tIMGUI_API bool          InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);\n\tIMGUI_API bool          InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = \"%.3f\", ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputFloat2(const char* label, float v[2], const char* format = \"%.3f\", ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputFloat3(const char* label, float v[3], const char* format = \"%.3f\", ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputFloat4(const char* label, float v[4], const char* format = \"%.3f\", ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = \"%.6f\", ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);\n\tIMGUI_API bool          InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);\n\n\t// Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.)\n\t// - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible.\n\t// - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x\n\tIMGUI_API bool          ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);\n\tIMGUI_API bool          ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0);\n\tIMGUI_API bool          ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);\n\tIMGUI_API bool          ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL);\n\tIMGUI_API bool          ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed.\n\tIMGUI_API void          SetColorEditOptions(ImGuiColorEditFlags flags);                     // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls.\n\n\t// Widgets: Trees\n\t// - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents.\n\tIMGUI_API bool          TreeNode(const char* label);\n\tIMGUI_API bool          TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2);   // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet().\n\tIMGUI_API bool          TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2);   // \"\n\tIMGUI_API bool          TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2);\n\tIMGUI_API bool          TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2);\n\tIMGUI_API bool          TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0);\n\tIMGUI_API bool          TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);\n\tIMGUI_API bool          TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);\n\tIMGUI_API bool          TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);\n\tIMGUI_API bool          TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);\n\tIMGUI_API void          TreePush(const char* str_id);                                       // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired.\n\tIMGUI_API void          TreePush(const void* ptr_id);                                       // \"\n\tIMGUI_API void          TreePop();                                                          // ~ Unindent()+PopId()\n\tIMGUI_API float         GetTreeNodeToLabelSpacing();                                        // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode\n\tIMGUI_API bool          CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0);  // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().\n\tIMGUI_API bool          CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header.\n\tIMGUI_API void          SetNextItemOpen(bool is_open, ImGuiCond cond = 0);                  // set next TreeNode/CollapsingHeader open state.\n\n\t// Widgets: Selectables\n\t// - A selectable highlights when hovered, and can display another color when selected.\n\t// - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous.\n\tIMGUI_API bool          Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // \"bool selected\" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height\n\tIMGUI_API bool          Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0));      // \"bool* p_selected\" point to the selection state (read-write), as a convenient helper.\n\n\t// Widgets: List Boxes\n\t// - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes.\n\t// - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items.\n\t// - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created.\n\t// - Choose frame width:   size.x > 0.0f: custom  /  size.x < 0.0f or -FLT_MIN: right-align   /  size.x = 0.0f (default): use current ItemWidth\n\t// - Choose frame height:  size.y > 0.0f: custom  /  size.y < 0.0f or -FLT_MIN: bottom-align  /  size.y = 0.0f (default): arbitrary default height which can fit ~7 items\n\tIMGUI_API bool          BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region\n\tIMGUI_API void          EndListBox();                                                       // only call EndListBox() if BeginListBox() returned true!\n\tIMGUI_API bool          ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1);\n\tIMGUI_API bool          ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);\n\n\t// Widgets: Data Plotting\n\t// - Consider using ImPlot (https://github.com/epezent/implot) which is much better!\n\tIMGUI_API void          PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));\n\tIMGUI_API void          PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));\n\tIMGUI_API void          PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));\n\tIMGUI_API void          PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));\n\n\t// Widgets: Value() Helpers.\n\t// - Those are merely shortcut to calling Text() with a format string. Output single value in \"name: value\" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)\n\tIMGUI_API void          Value(const char* prefix, bool b);\n\tIMGUI_API void          Value(const char* prefix, int v);\n\tIMGUI_API void          Value(const char* prefix, unsigned int v);\n\tIMGUI_API void          Value(const char* prefix, float v, const char* float_format = NULL);\n\n\t// Widgets: Menus\n\t// - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar.\n\t// - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it.\n\t// - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it.\n\t// - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment.\n\tIMGUI_API bool          BeginMenuBar();                                                     // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).\n\tIMGUI_API void          EndMenuBar();                                                       // only call EndMenuBar() if BeginMenuBar() returns true!\n\tIMGUI_API bool          BeginMainMenuBar();                                                 // create and append to a full screen menu-bar.\n\tIMGUI_API void          EndMainMenuBar();                                                   // only call EndMainMenuBar() if BeginMainMenuBar() returns true!\n\tIMGUI_API bool          BeginMenu(const char* label, bool enabled = true);                  // create a sub-menu entry. only call EndMenu() if this returns true!\n\tIMGUI_API void          EndMenu();                                                          // only call EndMenu() if BeginMenu() returns true!\n\tIMGUI_API bool          MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true);  // return true when activated.\n\tIMGUI_API bool          MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true);              // return true when activated + toggle (*p_selected) if p_selected != NULL\n\n\t// Tooltips\n\t// - Tooltips are windows following the mouse. They do not take focus away.\n\t// - A tooltip window can contain items of any types. SetTooltip() is a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom.\n\tIMGUI_API bool          BeginTooltip();                                                     // begin/append a tooltip window.\n\tIMGUI_API void          EndTooltip();                                                       // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true!\n\tIMGUI_API void          SetTooltip(const char* fmt, ...) IM_FMTARGS(1);                     // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous call to SetTooltip().\n\tIMGUI_API void          SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);\n\n\t// Tooltips: helpers for showing a tooltip when hovering an item\n\t// - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip) && BeginTooltip())' idiom.\n\t// - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip)) { SetTooltip(...); }' idiom.\n\t// - Where 'ImGuiHoveredFlags_Tooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'.\n\tIMGUI_API bool          BeginItemTooltip();                                                 // begin/append a tooltip window if preceding item was hovered.\n\tIMGUI_API void          SetItemTooltip(const char* fmt, ...) IM_FMTARGS(1);                 // set a text-only tooltip if preceeding item was hovered. override any previous call to SetTooltip().\n\tIMGUI_API void          SetItemTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);\n\n\t// Popups, Modals\n\t//  - They block normal mouse hovering detection (and therefore most mouse interactions) behind them.\n\t//  - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.\n\t//  - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls.\n\t//  - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time.\n\t//  - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered().\n\t//  - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack.\n\t//    This is sometimes leading to confusing mistakes. May rework this in the future.\n\n\t// Popups: begin/end functions\n\t//  - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window.\n\t//  - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, has a title bar.\n\tIMGUI_API bool          BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0);                         // return true if the popup is open, and you can start outputting to it.\n\tIMGUI_API bool          BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it.\n\tIMGUI_API void          EndPopup();                                                                         // only call EndPopup() if BeginPopupXXX() returns true!\n\n\t// Popups: open/close functions\n\t//  - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options.\n\t//  - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.\n\t//  - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually.\n\t//  - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options).\n\t//  - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup().\n\t//  - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened.\n\t//  - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter\n\tIMGUI_API void          OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0);                     // call to mark popup as open (don't call every frame!).\n\tIMGUI_API void          OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0);                             // id overload to facilitate calling from nested stacks\n\tIMGUI_API void          OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);   // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)\n\tIMGUI_API void          CloseCurrentPopup();                                                                // manually close the popup we have begin-ed into.\n\n\t// Popups: open+begin combined functions helpers\n\t//  - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking.\n\t//  - They are convenient to easily create context menus, hence the name.\n\t//  - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future.\n\t//  - IMPORTANT: Notice that we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight.\n\tIMGUI_API bool          BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);  // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!\n\tIMGUI_API bool          BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window.\n\tIMGUI_API bool          BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);  // open+begin popup when clicked in void (where there are no windows).\n\n\t// Popups: query functions\n\t//  - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack.\n\t//  - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack.\n\t//  - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open.\n\tIMGUI_API bool          IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0);                         // return true if the popup is open.\n\n\t// Tables\n\t// - Full-featured replacement for old Columns API.\n\t// - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary.\n\t// - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags.\n\t// The typical call flow is:\n\t// - 1. Call BeginTable(), early out if returning false.\n\t// - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults.\n\t// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows.\n\t// - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data.\n\t// - 5. Populate contents:\n\t//    - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column.\n\t//    - If you are using tables as a sort of grid, where every column is holding the same type of contents,\n\t//      you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex().\n\t//      TableNextColumn() will automatically wrap-around into the next row if needed.\n\t//    - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column!\n\t//    - Summary of possible call flow:\n\t//        --------------------------------------------------------------------------------------------------------\n\t//        TableNextRow() -> TableSetColumnIndex(0) -> Text(\"Hello 0\") -> TableSetColumnIndex(1) -> Text(\"Hello 1\")  // OK\n\t//        TableNextRow() -> TableNextColumn()      -> Text(\"Hello 0\") -> TableNextColumn()      -> Text(\"Hello 1\")  // OK\n\t//                          TableNextColumn()      -> Text(\"Hello 0\") -> TableNextColumn()      -> Text(\"Hello 1\")  // OK: TableNextColumn() automatically gets to next row!\n\t//        TableNextRow()                           -> Text(\"Hello 0\")                                               // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!\n\t//        --------------------------------------------------------------------------------------------------------\n\t// - 5. Call EndTable()\n\tIMGUI_API bool          BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);\n\tIMGUI_API void          EndTable();                                         // only call EndTable() if BeginTable() returns true!\n\tIMGUI_API void          TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.\n\tIMGUI_API bool          TableNextColumn();                                  // append into the next column (or first column of next row if currently in last column). Return true when column is visible.\n\tIMGUI_API bool          TableSetColumnIndex(int column_n);                  // append into the specified column. Return true when column is visible.\n\n\t// Tables: Headers & Columns declaration\n\t// - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc.\n\t// - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column.\n\t//   Headers are required to perform: reordering, sorting, and opening the context menu.\n\t//   The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody.\n\t// - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in\n\t//   some advanced use cases (e.g. adding custom widgets in header row).\n\t// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled.\n\tIMGUI_API void          TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0);\n\tIMGUI_API void          TableSetupScrollFreeze(int cols, int rows);         // lock columns/rows so they stay visible when scrolled.\n\tIMGUI_API void          TableHeadersRow();                                  // submit all headers cells based on data provided to TableSetupColumn() + submit context menu\n\tIMGUI_API void          TableHeader(const char* label);                     // submit one header cell manually (rarely used)\n\n\t// Tables: Sorting & Miscellaneous functions\n\t// - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting.\n\t//   When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have\n\t//   changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting,\n\t//   else you may wastefully sort your data every frame!\n\t// - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index.\n\tIMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs();                        // get latest sort specs for the table (NULL if not sorting).  Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable().\n\tIMGUI_API int                   TableGetColumnCount();                      // return number of columns (value passed to BeginTable)\n\tIMGUI_API int                   TableGetColumnIndex();                      // return current column index.\n\tIMGUI_API int                   TableGetRowIndex();                         // return current row index.\n\tIMGUI_API const char* TableGetColumnName(int column_n = -1);      // return \"\" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.\n\tIMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1);     // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column.\n\tIMGUI_API void                  TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)\n\tIMGUI_API void                  TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1);  // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details.\n\n\t// Legacy Columns API (prefer using Tables!)\n\t// - You can also use SameLine(pos_x) to mimic simplified columns.\n\tIMGUI_API void          Columns(int count = 1, const char* id = NULL, bool border = true);\n\tIMGUI_API void          NextColumn();                                                       // next column, defaults to current row or next row if the current row is finished\n\tIMGUI_API int           GetColumnIndex();                                                   // get current column index\n\tIMGUI_API float         GetColumnWidth(int column_index = -1);                              // get column width (in pixels). pass -1 to use current column\n\tIMGUI_API void          SetColumnWidth(int column_index, float width);                      // set column width (in pixels). pass -1 to use current column\n\tIMGUI_API float         GetColumnOffset(int column_index = -1);                             // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f\n\tIMGUI_API void          SetColumnOffset(int column_index, float offset_x);                  // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column\n\tIMGUI_API int           GetColumnsCount();\n\n\t// Tab Bars, Tabs\n\t// - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself.\n\tIMGUI_API bool          BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0);        // create and append into a TabBar\n\tIMGUI_API void          EndTabBar();                                                        // only call EndTabBar() if BeginTabBar() returns true!\n\tIMGUI_API bool          BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected.\n\tIMGUI_API void          EndTabItem();                                                       // only call EndTabItem() if BeginTabItem() returns true!\n\tIMGUI_API bool          TabItemButton(const char* label, ImGuiTabItemFlags flags = 0);      // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar.\n\tIMGUI_API void          SetTabItemClosed(const char* tab_or_docked_window_label);           // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.\n\n\t// Logging/Capture\n\t// - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging.\n\tIMGUI_API void          LogToTTY(int auto_open_depth = -1);                                 // start logging to tty (stdout)\n\tIMGUI_API void          LogToFile(int auto_open_depth = -1, const char* filename = NULL);   // start logging to file\n\tIMGUI_API void          LogToClipboard(int auto_open_depth = -1);                           // start logging to OS clipboard\n\tIMGUI_API void          LogFinish();                                                        // stop logging (close file, etc.)\n\tIMGUI_API void          LogButtons();                                                       // helper to display buttons for logging to tty/file/clipboard\n\tIMGUI_API void          LogText(const char* fmt, ...) IM_FMTARGS(1);                        // pass text data straight to log (without being displayed)\n\tIMGUI_API void          LogTextV(const char* fmt, va_list args) IM_FMTLIST(1);\n\n\t// Drag and Drop\n\t// - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource().\n\t// - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget().\n\t// - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback \"...\" tooltip, see #1725)\n\t// - An item can be both drag source and drop target.\n\tIMGUI_API bool          BeginDragDropSource(ImGuiDragDropFlags flags = 0);                                      // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource()\n\tIMGUI_API bool          SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0);  // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. Return true when payload has been accepted.\n\tIMGUI_API void          EndDragDropSource();                                                                    // only call EndDragDropSource() if BeginDragDropSource() returns true!\n\tIMGUI_API bool                  BeginDragDropTarget();                                                          // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget()\n\tIMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0);          // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.\n\tIMGUI_API void                  EndDragDropTarget();                                                            // only call EndDragDropTarget() if BeginDragDropTarget() returns true!\n\tIMGUI_API const ImGuiPayload* GetDragDropPayload();                                                           // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.\n\n\t// Disabling [BETA API]\n\t// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)\n\t// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)\n\t// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.\n\tIMGUI_API void          BeginDisabled(bool disabled = true);\n\tIMGUI_API void          EndDisabled();\n\n\t// Clipping\n\t// - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only.\n\tIMGUI_API void          PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);\n\tIMGUI_API void          PopClipRect();\n\n\t// Focus, Activation\n\t// - Prefer using \"SetItemDefaultFocus()\" over \"if (IsWindowAppearing()) SetScrollHereY()\" when applicable to signify \"this is the default item\"\n\tIMGUI_API void          SetItemDefaultFocus();                                              // make last item the default focused item of a window.\n\tIMGUI_API void          SetKeyboardFocusHere(int offset = 0);                               // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.\n\n\t// Overlapping mode\n\tIMGUI_API void          SetNextItemAllowOverlap();                                          // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this.\n\n\t// Item/Widgets Utilities and Query Functions\n\t// - Most of the functions are referring to the previous Item that has been submitted.\n\t// - See Demo Window under \"Widgets->Querying Status\" for an interactive visualization of most of those functions.\n\tIMGUI_API bool          IsItemHovered(ImGuiHoveredFlags flags = 0);                         // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options.\n\tIMGUI_API bool          IsItemActive();                                                     // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false)\n\tIMGUI_API bool          IsItemFocused();                                                    // is the last item focused for keyboard/gamepad navigation?\n\tIMGUI_API bool          IsItemClicked(ImGuiMouseButton mouse_button = 0);                   // is the last item hovered and mouse clicked on? (**)  == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this is NOT equivalent to the behavior of e.g. Button(). Read comments in function definition.\n\tIMGUI_API bool          IsItemVisible();                                                    // is the last item visible? (items may be out of sight because of clipping/scrolling)\n\tIMGUI_API bool          IsItemEdited();                                                     // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the \"bool\" return value of many widgets.\n\tIMGUI_API bool          IsItemActivated();                                                  // was the last item just made active (item was previously inactive).\n\tIMGUI_API bool          IsItemDeactivated();                                                // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that require continuous editing.\n\tIMGUI_API bool          IsItemDeactivatedAfterEdit();                                       // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that require continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item).\n\tIMGUI_API bool          IsItemToggledOpen();                                                // was the last item open state toggled? set by TreeNode().\n\tIMGUI_API bool          IsAnyItemHovered();                                                 // is any item hovered?\n\tIMGUI_API bool          IsAnyItemActive();                                                  // is any item active?\n\tIMGUI_API bool          IsAnyItemFocused();                                                 // is any item focused?\n\tIMGUI_API ImGuiID       GetItemID();                                                        // get ID of last item (~~ often same ImGui::GetID(label) beforehand)\n\tIMGUI_API ImVec2        GetItemRectMin();                                                   // get upper-left bounding rectangle of the last item (screen space)\n\tIMGUI_API ImVec2        GetItemRectMax();                                                   // get lower-right bounding rectangle of the last item (screen space)\n\tIMGUI_API ImVec2        GetItemRectSize();                                                  // get size of last item\n\n\t// Viewports\n\t// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows.\n\t// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports.\n\t// - In the future we will extend this concept further to also represent Platform Monitor and support a \"no main platform window\" operation mode.\n\tIMGUI_API ImGuiViewport* GetMainViewport();                                                 // return primary/default viewport. This can never be NULL.\n\n\t// Background/Foreground Draw Lists\n\tIMGUI_API ImDrawList* GetBackgroundDrawList();                                            // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents.\n\tIMGUI_API ImDrawList* GetForegroundDrawList();                                            // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.\n\n\t// Miscellaneous Utilities\n\tIMGUI_API bool          IsRectVisible(const ImVec2& size);                                  // test if rectangle (of given size, starting from cursor position) is visible / not clipped.\n\tIMGUI_API bool          IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max);      // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side.\n\tIMGUI_API double        GetTime();                                                          // get global imgui time. incremented by io.DeltaTime every frame.\n\tIMGUI_API int           GetFrameCount();                                                    // get global imgui frame count. incremented by 1 every frame.\n\tIMGUI_API ImDrawListSharedData* GetDrawListSharedData();                                    // you may use this when creating your own ImDrawList instances.\n\tIMGUI_API const char* GetStyleColorName(ImGuiCol idx);                                    // get a string corresponding to the enum value (for display, saving, etc.).\n\tIMGUI_API void          SetStateStorage(ImGuiStorage* storage);                             // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it)\n\tIMGUI_API ImGuiStorage* GetStateStorage();\n\tIMGUI_API bool          BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame\n\tIMGUI_API void          EndChildFrame();                                                    // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window)\n\n\t// Text Utilities\n\tIMGUI_API ImVec2        CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);\n\n\t// Color Utilities\n\tIMGUI_API ImVec4        ColorConvertU32ToFloat4(ImU32 in);\n\tIMGUI_API ImU32         ColorConvertFloat4ToU32(const ImVec4& in);\n\tIMGUI_API void          ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v);\n\tIMGUI_API void          ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);\n\n\t// Inputs Utilities: Keyboard/Mouse/Gamepad\n\t// - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...).\n\t// - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values:\n\t//  - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey.\n\t//  - with    IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined).\n\tIMGUI_API bool          IsKeyDown(ImGuiKey key);                                            // is key being held.\n\tIMGUI_API bool          IsKeyPressed(ImGuiKey key, bool repeat = true);                     // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate\n\tIMGUI_API bool          IsKeyReleased(ImGuiKey key);                                        // was key released (went from Down to !Down)?\n\tIMGUI_API int           GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate);  // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate\n\tIMGUI_API const char* GetKeyName(ImGuiKey key);                                           // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared.\n\tIMGUI_API void          SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard);        // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting \"io.WantCaptureKeyboard = want_capture_keyboard\"; after the next NewFrame() call.\n\n\t// Inputs Utilities: Mouse specific\n\t// - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right.\n\t// - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle.\n\t// - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold')\n\tIMGUI_API bool          IsMouseDown(ImGuiMouseButton button);                               // is mouse button held?\n\tIMGUI_API bool          IsMouseClicked(ImGuiMouseButton button, bool repeat = false);       // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1.\n\tIMGUI_API bool          IsMouseReleased(ImGuiMouseButton button);                           // did mouse button released? (went from Down to !Down)\n\tIMGUI_API bool          IsMouseDoubleClicked(ImGuiMouseButton button);                      // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true)\n\tIMGUI_API int           GetMouseClickedCount(ImGuiMouseButton button);                      // return the number of successive mouse-clicks at the time where a click happen (otherwise 0).\n\tIMGUI_API bool          IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.\n\tIMGUI_API bool          IsMousePosValid(const ImVec2* mouse_pos = NULL);                    // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available\n\tIMGUI_API bool          IsAnyMouseDown();                                                   // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid.\n\tIMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls\n\tIMGUI_API ImVec2        GetMousePosOnOpeningCurrentPopup();                                 // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves)\n\tIMGUI_API bool          IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f);         // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)\n\tIMGUI_API ImVec2        GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f);   // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)\n\tIMGUI_API void          ResetMouseDragDelta(ImGuiMouseButton button = 0);                   //\n\tIMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you\n\tIMGUI_API void          SetMouseCursor(ImGuiMouseCursor cursor_type);                       // set desired mouse cursor shape\n\tIMGUI_API void          SetNextFrameWantCaptureMouse(bool want_capture_mouse);              // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instucts your app to ignore inputs). This is equivalent to setting \"io.WantCaptureMouse = want_capture_mouse;\" after the next NewFrame() call.\n\n\t// Clipboard Utilities\n\t// - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard.\n\tIMGUI_API const char* GetClipboardText();\n\tIMGUI_API void          SetClipboardText(const char* text);\n\n\t// Settings/.Ini Utilities\n\t// - The disk functions are automatically called if io.IniFilename != NULL (default is \"imgui.ini\").\n\t// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.\n\t// - Important: default value \"imgui.ini\" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables).\n\tIMGUI_API void          LoadIniSettingsFromDisk(const char* ini_filename);                  // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).\n\tIMGUI_API void          LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size = 0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.\n\tIMGUI_API void          SaveIniSettingsToDisk(const char* ini_filename);                    // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext).\n\tIMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL);               // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.\n\n\t// Debug Utilities\n\tIMGUI_API void          DebugTextEncoding(const char* text);\n\tIMGUI_API bool          DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro.\n\n\t// Memory Allocators\n\t// - Those functions are not reliant on the current context.\n\t// - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()\n\t//   for each static/DLL boundary you are calling from. Read \"Context and Memory Allocators\" section of imgui.cpp for more details.\n\tIMGUI_API void          SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data = NULL);\n\tIMGUI_API void          GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data);\n\tIMGUI_API void* MemAlloc(size_t size);\n\tIMGUI_API void          MemFree(void* ptr);\n} // namespace ImGui\n\n//-----------------------------------------------------------------------------\n// [SECTION] Flags & Enumerations\n//-----------------------------------------------------------------------------\n\n// Flags for ImGui::Begin()\n// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and io.ConfigWindowsMoveFromTitleBarOnly)\nenum ImGuiWindowFlags_\n{\n\tImGuiWindowFlags_None = 0,\n\tImGuiWindowFlags_NoTitleBar = 1 << 0,   // Disable title-bar\n\tImGuiWindowFlags_NoResize = 1 << 1,   // Disable user resizing with the lower-right grip\n\tImGuiWindowFlags_NoMove = 1 << 2,   // Disable user moving the window\n\tImGuiWindowFlags_NoScrollbar = 1 << 3,   // Disable scrollbars (window can still scroll with mouse or programmatically)\n\tImGuiWindowFlags_NoScrollWithMouse = 1 << 4,   // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.\n\tImGuiWindowFlags_NoCollapse = 1 << 5,   // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node).\n\tImGuiWindowFlags_AlwaysAutoResize = 1 << 6,   // Resize every window to its content every frame\n\tImGuiWindowFlags_NoBackground = 1 << 7,   // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f).\n\tImGuiWindowFlags_NoSavedSettings = 1 << 8,   // Never load/save settings in .ini file\n\tImGuiWindowFlags_NoMouseInputs = 1 << 9,   // Disable catching mouse, hovering test with pass through.\n\tImGuiWindowFlags_MenuBar = 1 << 10,  // Has a menu-bar\n\tImGuiWindowFlags_HorizontalScrollbar = 1 << 11,  // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the \"Horizontal Scrolling\" section.\n\tImGuiWindowFlags_NoFocusOnAppearing = 1 << 12,  // Disable taking focus when transitioning from hidden to visible state\n\tImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13,  // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus)\n\tImGuiWindowFlags_AlwaysVerticalScrollbar = 1 << 14,  // Always show vertical scrollbar (even if ContentSize.y < Size.y)\n\tImGuiWindowFlags_AlwaysHorizontalScrollbar = 1 << 15,  // Always show horizontal scrollbar (even if ContentSize.x < Size.x)\n\tImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16,  // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient)\n\tImGuiWindowFlags_NoNavInputs = 1 << 18,  // No gamepad/keyboard navigation within the window\n\tImGuiWindowFlags_NoNavFocus = 1 << 19,  // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)\n\tImGuiWindowFlags_UnsavedDocument = 1 << 20,  // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.\n\tImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,\n\tImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,\n\tImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,\n\n\t// [Internal]\n\tImGuiWindowFlags_NavFlattened = 1 << 23,  // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.\n\tImGuiWindowFlags_ChildWindow = 1 << 24,  // Don't use! For internal use by BeginChild()\n\tImGuiWindowFlags_Tooltip = 1 << 25,  // Don't use! For internal use by BeginTooltip()\n\tImGuiWindowFlags_Popup = 1 << 26,  // Don't use! For internal use by BeginPopup()\n\tImGuiWindowFlags_Modal = 1 << 27,  // Don't use! For internal use by BeginPopupModal()\n\tImGuiWindowFlags_ChildMenu = 1 << 28,  // Don't use! For internal use by BeginMenu()\n};\n\n// Flags for ImGui::InputText()\n// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive)\nenum ImGuiInputTextFlags_\n{\n\tImGuiInputTextFlags_None = 0,\n\tImGuiInputTextFlags_CharsDecimal = 1 << 0,   // Allow 0123456789.+-*/\n\tImGuiInputTextFlags_CharsHexadecimal = 1 << 1,   // Allow 0123456789ABCDEFabcdef\n\tImGuiInputTextFlags_CharsUppercase = 1 << 2,   // Turn a..z into A..Z\n\tImGuiInputTextFlags_CharsNoBlank = 1 << 3,   // Filter out spaces, tabs\n\tImGuiInputTextFlags_AutoSelectAll = 1 << 4,   // Select entire text when first taking mouse focus\n\tImGuiInputTextFlags_EnterReturnsTrue = 1 << 5,   // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function.\n\tImGuiInputTextFlags_CallbackCompletion = 1 << 6,   // Callback on pressing TAB (for completion handling)\n\tImGuiInputTextFlags_CallbackHistory = 1 << 7,   // Callback on pressing Up/Down arrows (for history handling)\n\tImGuiInputTextFlags_CallbackAlways = 1 << 8,   // Callback on each iteration. User code may query cursor position, modify text buffer.\n\tImGuiInputTextFlags_CallbackCharFilter = 1 << 9,   // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.\n\tImGuiInputTextFlags_AllowTabInput = 1 << 10,  // Pressing TAB input a '\\t' character into the text field\n\tImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11,  // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter).\n\tImGuiInputTextFlags_NoHorizontalScroll = 1 << 12,  // Disable following the cursor horizontally\n\tImGuiInputTextFlags_AlwaysOverwrite = 1 << 13,  // Overwrite mode\n\tImGuiInputTextFlags_ReadOnly = 1 << 14,  // Read-only mode\n\tImGuiInputTextFlags_Password = 1 << 15,  // Password mode, display all characters as '*'\n\tImGuiInputTextFlags_NoUndoRedo = 1 << 16,  // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().\n\tImGuiInputTextFlags_CharsScientific = 1 << 17,  // Allow 0123456789.+-*/eE (Scientific notation input)\n\tImGuiInputTextFlags_CallbackResize = 1 << 18,  // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)\n\tImGuiInputTextFlags_CallbackEdit = 1 << 19,  // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)\n\tImGuiInputTextFlags_EscapeClearsAll = 1 << 20,  // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)\n\n\t// Obsolete names\n\t//ImGuiInputTextFlags_AlwaysInsertMode  = ImGuiInputTextFlags_AlwaysOverwrite   // [renamed in 1.82] name was not matching behavior\n};\n\n// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*()\nenum ImGuiTreeNodeFlags_\n{\n\tImGuiTreeNodeFlags_None = 0,\n\tImGuiTreeNodeFlags_Selected = 1 << 0,   // Draw as selected\n\tImGuiTreeNodeFlags_Framed = 1 << 1,   // Draw frame with background (e.g. for CollapsingHeader)\n\tImGuiTreeNodeFlags_AllowOverlap = 1 << 2,   // Hit testing to allow subsequent widgets to overlap this one\n\tImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3,   // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack\n\tImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4,   // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)\n\tImGuiTreeNodeFlags_DefaultOpen = 1 << 5,   // Default node to be open\n\tImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6,   // Need double-click to open node\n\tImGuiTreeNodeFlags_OpenOnArrow = 1 << 7,   // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.\n\tImGuiTreeNodeFlags_Leaf = 1 << 8,   // No collapsing, no arrow (use as a convenience for leaf nodes).\n\tImGuiTreeNodeFlags_Bullet = 1 << 9,   // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag!\n\tImGuiTreeNodeFlags_FramePadding = 1 << 10,  // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().\n\tImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11,  // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.\n\tImGuiTreeNodeFlags_SpanFullWidth = 1 << 12,  // Extend hit box to the left-most and right-most edges (bypass the indented area).\n\tImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13,  // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)\n\t//ImGuiTreeNodeFlags_NoScrollOnOpen     = 1 << 14,  // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible\n\tImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog,\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap,  // Renamed in 1.89.7\n#endif\n};\n\n// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions.\n// - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat\n//   small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags.\n//   It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags.\n// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0.\n//   IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter\n//   and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly.\n// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later).\nenum ImGuiPopupFlags_\n{\n\tImGuiPopupFlags_None = 0,\n\tImGuiPopupFlags_MouseButtonLeft = 0,        // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left)\n\tImGuiPopupFlags_MouseButtonRight = 1,        // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right)\n\tImGuiPopupFlags_MouseButtonMiddle = 2,        // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle)\n\tImGuiPopupFlags_MouseButtonMask_ = 0x1F,\n\tImGuiPopupFlags_MouseButtonDefault_ = 1,\n\tImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5,   // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack\n\tImGuiPopupFlags_NoOpenOverItems = 1 << 6,   // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space\n\tImGuiPopupFlags_AnyPopupId = 1 << 7,   // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup.\n\tImGuiPopupFlags_AnyPopupLevel = 1 << 8,   // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level)\n\tImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel,\n};\n\n// Flags for ImGui::Selectable()\nenum ImGuiSelectableFlags_\n{\n\tImGuiSelectableFlags_None = 0,\n\tImGuiSelectableFlags_DontClosePopups = 1 << 0,   // Clicking this doesn't close parent popup window\n\tImGuiSelectableFlags_SpanAllColumns = 1 << 1,   // Selectable frame can span all columns (text will still fit in current column)\n\tImGuiSelectableFlags_AllowDoubleClick = 1 << 2,   // Generate press events on double clicks too\n\tImGuiSelectableFlags_Disabled = 1 << 3,   // Cannot be selected, display grayed out text\n\tImGuiSelectableFlags_AllowOverlap = 1 << 4,   // (WIP) Hit testing to allow subsequent widgets to overlap this one\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap,  // Renamed in 1.89.7\n#endif\n};\n\n// Flags for ImGui::BeginCombo()\nenum ImGuiComboFlags_\n{\n\tImGuiComboFlags_None = 0,\n\tImGuiComboFlags_PopupAlignLeft = 1 << 0,   // Align the popup toward the left by default\n\tImGuiComboFlags_HeightSmall = 1 << 1,   // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo()\n\tImGuiComboFlags_HeightRegular = 1 << 2,   // Max ~8 items visible (default)\n\tImGuiComboFlags_HeightLarge = 1 << 3,   // Max ~20 items visible\n\tImGuiComboFlags_HeightLargest = 1 << 4,   // As many fitting items as possible\n\tImGuiComboFlags_NoArrowButton = 1 << 5,   // Display on the preview box without the square arrow button\n\tImGuiComboFlags_NoPreview = 1 << 6,   // Display only a square arrow button\n\tImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest,\n};\n\n// Flags for ImGui::BeginTabBar()\nenum ImGuiTabBarFlags_\n{\n\tImGuiTabBarFlags_None = 0,\n\tImGuiTabBarFlags_Reorderable = 1 << 0,   // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list\n\tImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1,   // Automatically select new tabs when they appear\n\tImGuiTabBarFlags_TabListPopupButton = 1 << 2,   // Disable buttons to open the tab list popup\n\tImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.\n\tImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4,   // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)\n\tImGuiTabBarFlags_NoTooltip = 1 << 5,   // Disable tooltips when hovering a tab\n\tImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6,   // Resize tabs when they don't fit\n\tImGuiTabBarFlags_FittingPolicyScroll = 1 << 7,   // Add scroll buttons when tabs don't fit\n\tImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,\n\tImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown,\n};\n\n// Flags for ImGui::BeginTabItem()\nenum ImGuiTabItemFlags_\n{\n\tImGuiTabItemFlags_None = 0,\n\tImGuiTabItemFlags_UnsavedDocument = 1 << 0,   // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.\n\tImGuiTabItemFlags_SetSelected = 1 << 1,   // Trigger flag to programmatically make the tab selected when calling BeginTabItem()\n\tImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.\n\tImGuiTabItemFlags_NoPushId = 1 << 3,   // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()\n\tImGuiTabItemFlags_NoTooltip = 1 << 4,   // Disable tooltip for the given tab\n\tImGuiTabItemFlags_NoReorder = 1 << 5,   // Disable reordering this tab or having another tab cross over this tab\n\tImGuiTabItemFlags_Leading = 1 << 6,   // Enforce the tab position to the left of the tab bar (after the tab list popup button)\n\tImGuiTabItemFlags_Trailing = 1 << 7,   // Enforce the tab position to the right of the tab bar (before the scrolling buttons)\n};\n\n// Flags for ImGui::BeginTable()\n// - Important! Sizing policies have complex and subtle side effects, much more so than you would expect.\n//   Read comments/demos carefully + experiment with live demos to get acquainted with them.\n// - The DEFAULT sizing policies are:\n//    - Default to ImGuiTableFlags_SizingFixedFit    if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n//    - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off.\n// - When ScrollX is off:\n//    - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight.\n//    - Columns sizing policy allowed: Stretch (default), Fixed/Auto.\n//    - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all).\n//    - Stretch Columns will share the remaining width according to their respective weight.\n//    - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors.\n//      The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.\n//      (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing).\n// - When ScrollX is on:\n//    - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed\n//    - Columns sizing policy allowed: Fixed/Auto mostly.\n//    - Fixed Columns can be enlarged as needed. Table will show a horizontal scrollbar if needed.\n//    - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop.\n//    - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable().\n//      If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again.\n// - Read on documentation at the top of imgui_tables.cpp for details.\nenum ImGuiTableFlags_\n{\n\t// Features\n\tImGuiTableFlags_None = 0,\n\tImGuiTableFlags_Resizable = 1 << 0,   // Enable resizing columns.\n\tImGuiTableFlags_Reorderable = 1 << 1,   // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)\n\tImGuiTableFlags_Hideable = 1 << 2,   // Enable hiding/disabling columns in context menu.\n\tImGuiTableFlags_Sortable = 1 << 3,   // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.\n\tImGuiTableFlags_NoSavedSettings = 1 << 4,   // Disable persisting columns order, width and sort settings in the .ini file.\n\tImGuiTableFlags_ContextMenuInBody = 1 << 5,   // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().\n\t// Decorations\n\tImGuiTableFlags_RowBg = 1 << 6,   // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)\n\tImGuiTableFlags_BordersInnerH = 1 << 7,   // Draw horizontal borders between rows.\n\tImGuiTableFlags_BordersOuterH = 1 << 8,   // Draw horizontal borders at the top and bottom.\n\tImGuiTableFlags_BordersInnerV = 1 << 9,   // Draw vertical borders between columns.\n\tImGuiTableFlags_BordersOuterV = 1 << 10,  // Draw vertical borders on the left and right sides.\n\tImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders.\n\tImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders.\n\tImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders.\n\tImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders.\n\tImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter,   // Draw all borders.\n\tImGuiTableFlags_NoBordersInBody = 1 << 11,  // [ALPHA] Disable vertical borders in columns Body (borders will always appear in Headers). -> May move to style\n\tImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12,  // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers). -> May move to style\n\t// Sizing Policy (read above for defaults)\n\tImGuiTableFlags_SizingFixedFit = 1 << 13,  // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width.\n\tImGuiTableFlags_SizingFixedSame = 2 << 13,  // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible.\n\tImGuiTableFlags_SizingStretchProp = 3 << 13,  // Columns default to _WidthStretch with default weights proportional to each columns contents widths.\n\tImGuiTableFlags_SizingStretchSame = 4 << 13,  // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn().\n\t// Sizing Extra Options\n\tImGuiTableFlags_NoHostExtendX = 1 << 16,  // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used.\n\tImGuiTableFlags_NoHostExtendY = 1 << 17,  // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.\n\tImGuiTableFlags_NoKeepColumnsVisible = 1 << 18,  // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable.\n\tImGuiTableFlags_PreciseWidths = 1 << 19,  // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.\n\t// Clipping\n\tImGuiTableFlags_NoClip = 1 << 20,  // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().\n\t// Padding\n\tImGuiTableFlags_PadOuterX = 1 << 21,  // Default if BordersOuterV is on. Enable outermost padding. Generally desirable if you have headers.\n\tImGuiTableFlags_NoPadOuterX = 1 << 22,  // Default if BordersOuterV is off. Disable outermost padding.\n\tImGuiTableFlags_NoPadInnerX = 1 << 23,  // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).\n\t// Scrolling\n\tImGuiTableFlags_ScrollX = 1 << 24,  // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this creates a child window, ScrollY is currently generally recommended when using ScrollX.\n\tImGuiTableFlags_ScrollY = 1 << 25,  // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.\n\t// Sorting\n\tImGuiTableFlags_SortMulti = 1 << 26,  // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).\n\tImGuiTableFlags_SortTristate = 1 << 27,  // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).\n\n\t// [Internal] Combinations and masks\n\tImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame,\n};\n\n// Flags for ImGui::TableSetupColumn()\nenum ImGuiTableColumnFlags_\n{\n\t// Input configuration flags\n\tImGuiTableColumnFlags_None = 0,\n\tImGuiTableColumnFlags_Disabled = 1 << 0,   // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state)\n\tImGuiTableColumnFlags_DefaultHide = 1 << 1,   // Default as a hidden/disabled column.\n\tImGuiTableColumnFlags_DefaultSort = 1 << 2,   // Default as a sorting column.\n\tImGuiTableColumnFlags_WidthStretch = 1 << 3,   // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp).\n\tImGuiTableColumnFlags_WidthFixed = 1 << 4,   // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable).\n\tImGuiTableColumnFlags_NoResize = 1 << 5,   // Disable manual resizing.\n\tImGuiTableColumnFlags_NoReorder = 1 << 6,   // Disable manual reordering this column, this will also prevent other columns from crossing over this column.\n\tImGuiTableColumnFlags_NoHide = 1 << 7,   // Disable ability to hide/disable this column.\n\tImGuiTableColumnFlags_NoClip = 1 << 8,   // Disable clipping for this column (all NoClip columns will render in a same draw command).\n\tImGuiTableColumnFlags_NoSort = 1 << 9,   // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).\n\tImGuiTableColumnFlags_NoSortAscending = 1 << 10,  // Disable ability to sort in the ascending direction.\n\tImGuiTableColumnFlags_NoSortDescending = 1 << 11,  // Disable ability to sort in the descending direction.\n\tImGuiTableColumnFlags_NoHeaderLabel = 1 << 12,  // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu.\n\tImGuiTableColumnFlags_NoHeaderWidth = 1 << 13,  // Disable header text width contribution to automatic column width.\n\tImGuiTableColumnFlags_PreferSortAscending = 1 << 14,  // Make the initial sort direction Ascending when first sorting on this column (default).\n\tImGuiTableColumnFlags_PreferSortDescending = 1 << 15,  // Make the initial sort direction Descending when first sorting on this column.\n\tImGuiTableColumnFlags_IndentEnable = 1 << 16,  // Use current Indent value when entering cell (default for column 0).\n\tImGuiTableColumnFlags_IndentDisable = 1 << 17,  // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.\n\n\t// Output status flags, read-only via TableGetColumnFlags()\n\tImGuiTableColumnFlags_IsEnabled = 1 << 24,  // Status: is enabled == not hidden by user/api (referred to as \"Hide\" in _DefaultHide and _NoHide) flags.\n\tImGuiTableColumnFlags_IsVisible = 1 << 25,  // Status: is visible == is enabled AND not clipped by scrolling.\n\tImGuiTableColumnFlags_IsSorted = 1 << 26,  // Status: is currently part of the sort specs\n\tImGuiTableColumnFlags_IsHovered = 1 << 27,  // Status: is hovered by mouse\n\n\t// [Internal] Combinations and masks\n\tImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed,\n\tImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable,\n\tImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered,\n\tImGuiTableColumnFlags_NoDirectResize_ = 1 << 30,  // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge)\n};\n\n// Flags for ImGui::TableNextRow()\nenum ImGuiTableRowFlags_\n{\n\tImGuiTableRowFlags_None = 0,\n\tImGuiTableRowFlags_Headers = 1 << 0,   // Identify header row (set default background color + width of its contents accounted differently for auto column width)\n};\n\n// Enum for ImGui::TableSetBgColor()\n// Background colors are rendering in 3 layers:\n//  - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set.\n//  - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set.\n//  - Layer 2: draw with CellBg color if set.\n// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend with the existing color.\n// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows.\n// If you set the color of RowBg0 target, your color will override the existing RowBg0 color.\n// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color.\nenum ImGuiTableBgTarget_\n{\n\tImGuiTableBgTarget_None = 0,\n\tImGuiTableBgTarget_RowBg0 = 1,        // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used)\n\tImGuiTableBgTarget_RowBg1 = 2,        // Set row background color 1 (generally used for selection marking)\n\tImGuiTableBgTarget_CellBg = 3,        // Set cell background color (top-most color)\n};\n\n// Flags for ImGui::IsWindowFocused()\nenum ImGuiFocusedFlags_\n{\n\tImGuiFocusedFlags_None = 0,\n\tImGuiFocusedFlags_ChildWindows = 1 << 0,   // Return true if any children of the window is focused\n\tImGuiFocusedFlags_RootWindow = 1 << 1,   // Test from root window (top most parent of the current hierarchy)\n\tImGuiFocusedFlags_AnyWindow = 1 << 2,   // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ!\n\tImGuiFocusedFlags_NoPopupHierarchy = 1 << 3,   // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow)\n\t//ImGuiFocusedFlags_DockHierarchy               = 1 << 4,   // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)\n\tImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows,\n};\n\n// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered()\n// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ!\n// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls.\nenum ImGuiHoveredFlags_\n{\n\tImGuiHoveredFlags_None = 0,        // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them.\n\tImGuiHoveredFlags_ChildWindows = 1 << 0,   // IsWindowHovered() only: Return true if any children of the window is hovered\n\tImGuiHoveredFlags_RootWindow = 1 << 1,   // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy)\n\tImGuiHoveredFlags_AnyWindow = 1 << 2,   // IsWindowHovered() only: Return true if any window is hovered\n\tImGuiHoveredFlags_NoPopupHierarchy = 1 << 3,   // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow)\n\t//ImGuiHoveredFlags_DockHierarchy               = 1 << 4,   // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)\n\tImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5,   // Return true even if a popup window is normally blocking access to this item/window\n\t//ImGuiHoveredFlags_AllowWhenBlockedByModal     = 1 << 6,   // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.\n\tImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7,   // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.\n\tImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8,   // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item.\n\tImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9,   // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window.\n\tImGuiHoveredFlags_AllowWhenDisabled = 1 << 10,  // IsItemHovered() only: Return true even if the item is disabled\n\tImGuiHoveredFlags_NoNavOverride = 1 << 11,  // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse\n\tImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow,\n\tImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped,\n\tImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows,\n\n\t// Tooltips mode\n\t// - typically used in IsItemHovered() + SetTooltip() sequence.\n\t// - this is a shortcut to pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' where you can reconfigure desired behavior.\n\t//   e.g. 'TooltipHoveredFlagsForMouse' defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'.\n\t// - for frequently actioned or hovered items providing a tooltip, you want may to use ImGuiHoveredFlags_ForTooltip (stationary + delay) so the tooltip doesn't show too often.\n\t// - for items which main purpose is to be hovered, or items with low affordance, or in less consistent apps, prefer no delay or shorter delay.\n\tImGuiHoveredFlags_ForTooltip = 1 << 12,  // Shortcut for standard flags when using IsItemHovered() + SetTooltip() sequence.\n\n\t// (Advanced) Mouse Hovering delays.\n\t// - generally you can use ImGuiHoveredFlags_ForTooltip to use application-standardized flags.\n\t// - use those if you need specific overrides.\n\tImGuiHoveredFlags_Stationary = 1 << 13,  // Require mouse to be stationary for style.HoverStationaryDelay (~0.15 sec) _at least one time_. After this, can move on same item/window. Using the stationary test tends to reduces the need for a long delay.\n\tImGuiHoveredFlags_DelayNone = 1 << 14,  // IsItemHovered() only: Return true immediately (default). As this is the default you generally ignore this.\n\tImGuiHoveredFlags_DelayShort = 1 << 15,  // IsItemHovered() only: Return true after style.HoverDelayShort elapsed (~0.15 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item).\n\tImGuiHoveredFlags_DelayNormal = 1 << 16,  // IsItemHovered() only: Return true after style.HoverDelayNormal elapsed (~0.40 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item).\n\tImGuiHoveredFlags_NoSharedDelay = 1 << 17,  // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays)\n};\n\n// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload()\nenum ImGuiDragDropFlags_\n{\n\tImGuiDragDropFlags_None = 0,\n\t// BeginDragDropSource() flags\n\tImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0,   // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior.\n\tImGuiDragDropFlags_SourceNoDisableHover = 1 << 1,   // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disables this behavior so you can still call IsItemHovered() on the source item.\n\tImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2,   // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.\n\tImGuiDragDropFlags_SourceAllowNullID = 1 << 3,   // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.\n\tImGuiDragDropFlags_SourceExtern = 1 << 4,   // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.\n\tImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5,   // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)\n\t// AcceptDragDropPayload() flags\n\tImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10,  // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.\n\tImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11,  // Do not draw the default highlight rectangle when hovering over target.\n\tImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12,  // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site.\n\tImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery.\n};\n\n// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui.\n#define IMGUI_PAYLOAD_TYPE_COLOR_3F     \"_COL3F\"    // float[3]: Standard type for colors, without alpha. User code may use this type.\n#define IMGUI_PAYLOAD_TYPE_COLOR_4F     \"_COL4F\"    // float[4]: Standard type for colors. User code may use this type.\n\n// A primary data type\nenum ImGuiDataType_\n{\n\tImGuiDataType_S8,       // signed char / char (with sensible compilers)\n\tImGuiDataType_U8,       // unsigned char\n\tImGuiDataType_S16,      // short\n\tImGuiDataType_U16,      // unsigned short\n\tImGuiDataType_S32,      // int\n\tImGuiDataType_U32,      // unsigned int\n\tImGuiDataType_S64,      // long long / __int64\n\tImGuiDataType_U64,      // unsigned long long / unsigned __int64\n\tImGuiDataType_Float,    // float\n\tImGuiDataType_Double,   // double\n\tImGuiDataType_COUNT\n};\n\n// A cardinal direction\nenum ImGuiDir_\n{\n\tImGuiDir_None = -1,\n\tImGuiDir_Left = 0,\n\tImGuiDir_Right = 1,\n\tImGuiDir_Up = 2,\n\tImGuiDir_Down = 3,\n\tImGuiDir_COUNT\n};\n\n// A sorting direction\nenum ImGuiSortDirection_\n{\n\tImGuiSortDirection_None = 0,\n\tImGuiSortDirection_Ascending = 1,    // Ascending = 0->9, A->Z etc.\n\tImGuiSortDirection_Descending = 2     // Descending = 9->0, Z->A etc.\n};\n\n// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values.\n// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87).\n// Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey.\n// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921\n// Note that \"Keys\" related to physical keys and are not the same concept as input \"Characters\", the later are submitted via io.AddInputCharacter().\nenum ImGuiKey : int\n{\n\t// Keyboard\n\tImGuiKey_None = 0,\n\tImGuiKey_Tab = 512,             // == ImGuiKey_NamedKey_BEGIN\n\tImGuiKey_LeftArrow,\n\tImGuiKey_RightArrow,\n\tImGuiKey_UpArrow,\n\tImGuiKey_DownArrow,\n\tImGuiKey_PageUp,\n\tImGuiKey_PageDown,\n\tImGuiKey_Home,\n\tImGuiKey_End,\n\tImGuiKey_Insert,\n\tImGuiKey_Delete,\n\tImGuiKey_Backspace,\n\tImGuiKey_Space,\n\tImGuiKey_Enter,\n\tImGuiKey_Escape,\n\tImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper,\n\tImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper,\n\tImGuiKey_Menu,\n\tImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9,\n\tImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J,\n\tImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T,\n\tImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z,\n\tImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6,\n\tImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12,\n\tImGuiKey_Apostrophe,        // '\n\tImGuiKey_Comma,             // ,\n\tImGuiKey_Minus,             // -\n\tImGuiKey_Period,            // .\n\tImGuiKey_Slash,             // /\n\tImGuiKey_Semicolon,         // ;\n\tImGuiKey_Equal,             // =\n\tImGuiKey_LeftBracket,       // [\n\tImGuiKey_Backslash,         // \\ (this text inhibit multiline comment caused by backslash)\n\tImGuiKey_RightBracket,      // ]\n\tImGuiKey_GraveAccent,       // `\n\tImGuiKey_CapsLock,\n\tImGuiKey_ScrollLock,\n\tImGuiKey_NumLock,\n\tImGuiKey_PrintScreen,\n\tImGuiKey_Pause,\n\tImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4,\n\tImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9,\n\tImGuiKey_KeypadDecimal,\n\tImGuiKey_KeypadDivide,\n\tImGuiKey_KeypadMultiply,\n\tImGuiKey_KeypadSubtract,\n\tImGuiKey_KeypadAdd,\n\tImGuiKey_KeypadEnter,\n\tImGuiKey_KeypadEqual,\n\n\t// Gamepad (some of those are analog values, 0.0f to 1.0f)                          // NAVIGATION ACTION\n\t// (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets)\n\tImGuiKey_GamepadStart,          // Menu (Xbox)      + (Switch)   Start/Options (PS)\n\tImGuiKey_GamepadBack,           // View (Xbox)      - (Switch)   Share (PS)\n\tImGuiKey_GamepadFaceLeft,       // X (Xbox)         Y (Switch)   Square (PS)        // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows)\n\tImGuiKey_GamepadFaceRight,      // B (Xbox)         A (Switch)   Circle (PS)        // Cancel / Close / Exit\n\tImGuiKey_GamepadFaceUp,         // Y (Xbox)         X (Switch)   Triangle (PS)      // Text Input / On-screen Keyboard\n\tImGuiKey_GamepadFaceDown,       // A (Xbox)         B (Switch)   Cross (PS)         // Activate / Open / Toggle / Tweak\n\tImGuiKey_GamepadDpadLeft,       // D-pad Left                                       // Move / Tweak / Resize Window (in Windowing mode)\n\tImGuiKey_GamepadDpadRight,      // D-pad Right                                      // Move / Tweak / Resize Window (in Windowing mode)\n\tImGuiKey_GamepadDpadUp,         // D-pad Up                                         // Move / Tweak / Resize Window (in Windowing mode)\n\tImGuiKey_GamepadDpadDown,       // D-pad Down                                       // Move / Tweak / Resize Window (in Windowing mode)\n\tImGuiKey_GamepadL1,             // L Bumper (Xbox)  L (Switch)   L1 (PS)            // Tweak Slower / Focus Previous (in Windowing mode)\n\tImGuiKey_GamepadR1,             // R Bumper (Xbox)  R (Switch)   R1 (PS)            // Tweak Faster / Focus Next (in Windowing mode)\n\tImGuiKey_GamepadL2,             // L Trig. (Xbox)   ZL (Switch)  L2 (PS) [Analog]\n\tImGuiKey_GamepadR2,             // R Trig. (Xbox)   ZR (Switch)  R2 (PS) [Analog]\n\tImGuiKey_GamepadL3,             // L Stick (Xbox)   L3 (Switch)  L3 (PS)\n\tImGuiKey_GamepadR3,             // R Stick (Xbox)   R3 (Switch)  R3 (PS)\n\tImGuiKey_GamepadLStickLeft,     // [Analog]                                         // Move Window (in Windowing mode)\n\tImGuiKey_GamepadLStickRight,    // [Analog]                                         // Move Window (in Windowing mode)\n\tImGuiKey_GamepadLStickUp,       // [Analog]                                         // Move Window (in Windowing mode)\n\tImGuiKey_GamepadLStickDown,     // [Analog]                                         // Move Window (in Windowing mode)\n\tImGuiKey_GamepadRStickLeft,     // [Analog]\n\tImGuiKey_GamepadRStickRight,    // [Analog]\n\tImGuiKey_GamepadRStickUp,       // [Analog]\n\tImGuiKey_GamepadRStickDown,     // [Analog]\n\n\t// Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls)\n\t// - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API.\n\tImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY,\n\n\t// [Internal] Reserved for mod storage\n\tImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper,\n\tImGuiKey_COUNT,\n\n\t// Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls)\n\t// - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing\n\t//   them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc.\n\t// - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those\n\t//   and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl).\n\t// - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys.\n\t//   In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and\n\t//   backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user...\n\tImGuiMod_None = 0,\n\tImGuiMod_Ctrl = 1 << 12, // Ctrl\n\tImGuiMod_Shift = 1 << 13, // Shift\n\tImGuiMod_Alt = 1 << 14, // Option/Menu\n\tImGuiMod_Super = 1 << 15, // Cmd/Super/Windows\n\tImGuiMod_Shortcut = 1 << 11, // Alias for Ctrl (non-macOS) _or_ Super (macOS).\n\tImGuiMod_Mask_ = 0xF800,  // 5-bits\n\n\t// [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array.\n\t// We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE)\n\t// If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END.\n\tImGuiKey_NamedKey_BEGIN = 512,\n\tImGuiKey_NamedKey_END = ImGuiKey_COUNT,\n\tImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN,\n#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT,  // Size of KeysData[]: only hold named keys\n\tImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN,  // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index.\n#else\n\tImGuiKey_KeysData_SIZE = ImGuiKey_COUNT,           // Size of KeysData[]: hold legacy 0..512 keycodes + named keys\n\tImGuiKey_KeysData_OFFSET = 0,                        // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index.\n#endif\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89\n\tImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter,    // Renamed in 1.87\n#endif\n};\n\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n// OBSOLETED in 1.88 (from July 2022): ImGuiNavInput and io.NavInputs[].\n// Official backends between 1.60 and 1.86: will keep working and feed gamepad inputs as long as IMGUI_DISABLE_OBSOLETE_KEYIO is not set.\n// Custom backends: feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums.\nenum ImGuiNavInput\n{\n\tImGuiNavInput_Activate, ImGuiNavInput_Cancel, ImGuiNavInput_Input, ImGuiNavInput_Menu, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_DpadDown,\n\tImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp, ImGuiNavInput_LStickDown, ImGuiNavInput_FocusPrev, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakSlow, ImGuiNavInput_TweakFast,\n\tImGuiNavInput_COUNT,\n};\n#endif\n\n// Configuration flags stored in io.ConfigFlags. Set by user/application.\nenum ImGuiConfigFlags_\n{\n\tImGuiConfigFlags_None = 0,\n\tImGuiConfigFlags_NavEnableKeyboard = 1 << 0,   // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate.\n\tImGuiConfigFlags_NavEnableGamepad = 1 << 1,   // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad.\n\tImGuiConfigFlags_NavEnableSetMousePos = 1 << 2,   // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth.\n\tImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3,   // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set.\n\tImGuiConfigFlags_NoMouse = 1 << 4,   // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend.\n\tImGuiConfigFlags_NoMouseCursorChange = 1 << 5,   // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.\n\n\t// User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui)\n\tImGuiConfigFlags_IsSRGB = 1 << 20,  // Application is SRGB-aware.\n\tImGuiConfigFlags_IsTouchScreen = 1 << 21,  // Application is using a touch screen instead of a mouse.\n};\n\n// Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend.\nenum ImGuiBackendFlags_\n{\n\tImGuiBackendFlags_None = 0,\n\tImGuiBackendFlags_HasGamepad = 1 << 0,   // Backend Platform supports gamepad and currently has one connected.\n\tImGuiBackendFlags_HasMouseCursors = 1 << 1,   // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape.\n\tImGuiBackendFlags_HasSetMousePos = 1 << 2,   // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).\n\tImGuiBackendFlags_RendererHasVtxOffset = 1 << 3,   // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices.\n};\n\n// Enumeration for PushStyleColor() / PopStyleColor()\nenum ImGuiCol_\n{\n\tImGuiCol_Text,\n\tImGuiCol_TextDisabled,\n\tImGuiCol_WindowBg,              // Background of normal windows\n\tImGuiCol_ChildBg,               // Background of child windows\n\tImGuiCol_PopupBg,               // Background of popups, menus, tooltips windows\n\tImGuiCol_Border,\n\tImGuiCol_BorderShadow,\n\tImGuiCol_FrameBg,               // Background of checkbox, radio button, plot, slider, text input\n\tImGuiCol_FrameBgHovered,\n\tImGuiCol_FrameBgActive,\n\tImGuiCol_TitleBg,\n\tImGuiCol_TitleBgActive,\n\tImGuiCol_TitleBgCollapsed,\n\tImGuiCol_MenuBarBg,\n\tImGuiCol_ScrollbarBg,\n\tImGuiCol_ScrollbarGrab,\n\tImGuiCol_ScrollbarGrabHovered,\n\tImGuiCol_ScrollbarGrabActive,\n\tImGuiCol_CheckMark,\n\tImGuiCol_SliderGrab,\n\tImGuiCol_SliderGrabActive,\n\tImGuiCol_Button,\n\tImGuiCol_ButtonHovered,\n\tImGuiCol_ButtonActive,\n\tImGuiCol_Header,                // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem\n\tImGuiCol_HeaderHovered,\n\tImGuiCol_HeaderActive,\n\tImGuiCol_Separator,\n\tImGuiCol_SeparatorHovered,\n\tImGuiCol_SeparatorActive,\n\tImGuiCol_ResizeGrip,            // Resize grip in lower-right and lower-left corners of windows.\n\tImGuiCol_ResizeGripHovered,\n\tImGuiCol_ResizeGripActive,\n\tImGuiCol_Tab,                   // TabItem in a TabBar\n\tImGuiCol_TabHovered,\n\tImGuiCol_TabActive,\n\tImGuiCol_TabUnfocused,\n\tImGuiCol_TabUnfocusedActive,\n\tImGuiCol_PlotLines,\n\tImGuiCol_PlotLinesHovered,\n\tImGuiCol_PlotHistogram,\n\tImGuiCol_PlotHistogramHovered,\n\tImGuiCol_TableHeaderBg,         // Table header background\n\tImGuiCol_TableBorderStrong,     // Table outer and header borders (prefer using Alpha=1.0 here)\n\tImGuiCol_TableBorderLight,      // Table inner borders (prefer using Alpha=1.0 here)\n\tImGuiCol_TableRowBg,            // Table row background (even rows)\n\tImGuiCol_TableRowBgAlt,         // Table row background (odd rows)\n\tImGuiCol_TextSelectedBg,\n\tImGuiCol_DragDropTarget,        // Rectangle highlighting a drop target\n\tImGuiCol_NavHighlight,          // Gamepad/keyboard: current highlighted item\n\tImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB\n\tImGuiCol_NavWindowingDimBg,     // Darken/colorize entire screen behind the CTRL+TAB window list, when active\n\tImGuiCol_ModalWindowDimBg,      // Darken/colorize entire screen behind a modal window, when one is active\n\tImGuiCol_COUNT\n};\n\n// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure.\n// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code.\n//   During initialization or between frames, feel free to just poke into ImGuiStyle directly.\n// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description.\n//   In Visual Studio IDE: CTRL+comma (\"Edit.GoToAll\") can follow symbols in comments, whereas CTRL+F12 (\"Edit.GoToImplementation\") cannot.\n//   With Visual Assist installed: ALT+G (\"VAssistX.GoToImplementation\") can also follow symbols in comments.\n// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type.\nenum ImGuiStyleVar_\n{\n\t// Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions)\n\tImGuiStyleVar_Alpha,               // float     Alpha\n\tImGuiStyleVar_DisabledAlpha,       // float     DisabledAlpha\n\tImGuiStyleVar_WindowPadding,       // ImVec2    WindowPadding\n\tImGuiStyleVar_WindowRounding,      // float     WindowRounding\n\tImGuiStyleVar_WindowBorderSize,    // float     WindowBorderSize\n\tImGuiStyleVar_WindowMinSize,       // ImVec2    WindowMinSize\n\tImGuiStyleVar_WindowTitleAlign,    // ImVec2    WindowTitleAlign\n\tImGuiStyleVar_ChildRounding,       // float     ChildRounding\n\tImGuiStyleVar_ChildBorderSize,     // float     ChildBorderSize\n\tImGuiStyleVar_PopupRounding,       // float     PopupRounding\n\tImGuiStyleVar_PopupBorderSize,     // float     PopupBorderSize\n\tImGuiStyleVar_FramePadding,        // ImVec2    FramePadding\n\tImGuiStyleVar_FrameRounding,       // float     FrameRounding\n\tImGuiStyleVar_FrameBorderSize,     // float     FrameBorderSize\n\tImGuiStyleVar_ItemSpacing,         // ImVec2    ItemSpacing\n\tImGuiStyleVar_ItemInnerSpacing,    // ImVec2    ItemInnerSpacing\n\tImGuiStyleVar_IndentSpacing,       // float     IndentSpacing\n\tImGuiStyleVar_CellPadding,         // ImVec2    CellPadding\n\tImGuiStyleVar_ScrollbarSize,       // float     ScrollbarSize\n\tImGuiStyleVar_ScrollbarRounding,   // float     ScrollbarRounding\n\tImGuiStyleVar_GrabMinSize,         // float     GrabMinSize\n\tImGuiStyleVar_GrabRounding,        // float     GrabRounding\n\tImGuiStyleVar_TabRounding,         // float     TabRounding\n\tImGuiStyleVar_ButtonTextAlign,     // ImVec2    ButtonTextAlign\n\tImGuiStyleVar_SelectableTextAlign, // ImVec2    SelectableTextAlign\n\tImGuiStyleVar_SeparatorTextBorderSize,// float  SeparatorTextBorderSize\n\tImGuiStyleVar_SeparatorTextAlign,  // ImVec2    SeparatorTextAlign\n\tImGuiStyleVar_SeparatorTextPadding,// ImVec2    SeparatorTextPadding\n\tImGuiStyleVar_COUNT\n};\n\n// Flags for InvisibleButton() [extended in imgui_internal.h]\nenum ImGuiButtonFlags_\n{\n\tImGuiButtonFlags_None = 0,\n\tImGuiButtonFlags_MouseButtonLeft = 1 << 0,   // React on left mouse button (default)\n\tImGuiButtonFlags_MouseButtonRight = 1 << 1,   // React on right mouse button\n\tImGuiButtonFlags_MouseButtonMiddle = 1 << 2,   // React on center mouse button\n\n\t// [Internal]\n\tImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle,\n\tImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft,\n};\n\n// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton()\nenum ImGuiColorEditFlags_\n{\n\tImGuiColorEditFlags_None = 0,\n\tImGuiColorEditFlags_NoAlpha = 1 << 1,   //              // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer).\n\tImGuiColorEditFlags_NoPicker = 1 << 2,   //              // ColorEdit: disable picker when clicking on color square.\n\tImGuiColorEditFlags_NoOptions = 1 << 3,   //              // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview.\n\tImGuiColorEditFlags_NoSmallPreview = 1 << 4,   //              // ColorEdit, ColorPicker: disable color square preview next to the inputs. (e.g. to show only the inputs)\n\tImGuiColorEditFlags_NoInputs = 1 << 5,   //              // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview color square).\n\tImGuiColorEditFlags_NoTooltip = 1 << 6,   //              // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview.\n\tImGuiColorEditFlags_NoLabel = 1 << 7,   //              // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker).\n\tImGuiColorEditFlags_NoSidePreview = 1 << 8,   //              // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead.\n\tImGuiColorEditFlags_NoDragDrop = 1 << 9,   //              // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source.\n\tImGuiColorEditFlags_NoBorder = 1 << 10,  //              // ColorButton: disable border (which is enforced by default)\n\n\t// User Options (right-click on widget to change some of them).\n\tImGuiColorEditFlags_AlphaBar = 1 << 16,  //              // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker.\n\tImGuiColorEditFlags_AlphaPreview = 1 << 17,  //              // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque.\n\tImGuiColorEditFlags_AlphaPreviewHalf = 1 << 18,  //              // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque.\n\tImGuiColorEditFlags_HDR = 1 << 19,  //              // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well).\n\tImGuiColorEditFlags_DisplayRGB = 1 << 20,  // [Display]    // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex.\n\tImGuiColorEditFlags_DisplayHSV = 1 << 21,  // [Display]    // \"\n\tImGuiColorEditFlags_DisplayHex = 1 << 22,  // [Display]    // \"\n\tImGuiColorEditFlags_Uint8 = 1 << 23,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255.\n\tImGuiColorEditFlags_Float = 1 << 24,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers.\n\tImGuiColorEditFlags_PickerHueBar = 1 << 25,  // [Picker]     // ColorPicker: bar for Hue, rectangle for Sat/Value.\n\tImGuiColorEditFlags_PickerHueWheel = 1 << 26,  // [Picker]     // ColorPicker: wheel for Hue, triangle for Sat/Value.\n\tImGuiColorEditFlags_InputRGB = 1 << 27,  // [Input]      // ColorEdit, ColorPicker: input and output data in RGB format.\n\tImGuiColorEditFlags_InputHSV = 1 << 28,  // [Input]      // ColorEdit, ColorPicker: input and output data in HSV format.\n\n\t// Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to\n\t// override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup.\n\tImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar,\n\n\t// [Internal] Masks\n\tImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex,\n\tImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,\n\tImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,\n\tImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV,\n\n\t// Obsolete names\n\t//ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex  // [renamed in 1.69]\n};\n\n// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.\n// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them.\n// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigDragClickToInputText)\nenum ImGuiSliderFlags_\n{\n\tImGuiSliderFlags_None = 0,\n\tImGuiSliderFlags_AlwaysClamp = 1 << 4,       // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.\n\tImGuiSliderFlags_Logarithmic = 1 << 5,       // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.\n\tImGuiSliderFlags_NoRoundToFormat = 1 << 6,       // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)\n\tImGuiSliderFlags_NoInput = 1 << 7,       // Disable CTRL+Click or Enter key allowing to input text directly into the widget\n\tImGuiSliderFlags_InvalidMask_ = 0x7000000F,   // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.\n\n\t// Obsolete names\n\t//ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79]\n};\n\n// Identify a mouse button.\n// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience.\nenum ImGuiMouseButton_\n{\n\tImGuiMouseButton_Left = 0,\n\tImGuiMouseButton_Right = 1,\n\tImGuiMouseButton_Middle = 2,\n\tImGuiMouseButton_COUNT = 5\n};\n\n// Enumeration for GetMouseCursor()\n// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here\nenum ImGuiMouseCursor_\n{\n\tImGuiMouseCursor_None = -1,\n\tImGuiMouseCursor_Arrow = 0,\n\tImGuiMouseCursor_TextInput,         // When hovering over InputText, etc.\n\tImGuiMouseCursor_ResizeAll,         // (Unused by Dear ImGui functions)\n\tImGuiMouseCursor_ResizeNS,          // When hovering over a horizontal border\n\tImGuiMouseCursor_ResizeEW,          // When hovering over a vertical border or a column\n\tImGuiMouseCursor_ResizeNESW,        // When hovering over the bottom-left corner of a window\n\tImGuiMouseCursor_ResizeNWSE,        // When hovering over the bottom-right corner of a window\n\tImGuiMouseCursor_Hand,              // (Unused by Dear ImGui functions. Use for e.g. hyperlinks)\n\tImGuiMouseCursor_NotAllowed,        // When hovering something with disallowed interaction. Usually a crossed circle.\n\tImGuiMouseCursor_COUNT\n};\n\n// Enumeration for AddMouseSourceEvent() actual source of Mouse Input data.\n// Historically we use \"Mouse\" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent()\n// But that \"Mouse\" data can come from different source which occasionally may be useful for application to know about.\n// You can submit a change of pointer type using io.AddMouseSourceEvent().\nenum ImGuiMouseSource : int\n{\n\tImGuiMouseSource_Mouse = 0,         // Input is coming from an actual mouse.\n\tImGuiMouseSource_TouchScreen,       // Input is coming from a touch screen (no hovering prior to initial press, less precise initial press aiming, dual-axis wheeling possible).\n\tImGuiMouseSource_Pen,               // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling rates).\n\tImGuiMouseSource_COUNT\n};\n\n// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions\n// Represent a condition.\n// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always.\nenum ImGuiCond_\n{\n\tImGuiCond_None = 0,        // No condition (always set the variable), same as _Always\n\tImGuiCond_Always = 1 << 0,   // No condition (always set the variable), same as _None\n\tImGuiCond_Once = 1 << 1,   // Set the variable once per runtime session (only the first call will succeed)\n\tImGuiCond_FirstUseEver = 1 << 2,   // Set the variable if the object/window has no persistently saved data (no entry in .ini file)\n\tImGuiCond_Appearing = 1 << 3,   // Set the variable if the object/window is appearing after being hidden/inactive (or the first time)\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Helpers: Memory allocations macros, ImVector<>\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()\n// We call C++ constructor on own allocated memory via the placement \"new(ptr) Type()\" syntax.\n// Defining a custom placement new() with a custom parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.\n//-----------------------------------------------------------------------------\n\nstruct ImNewWrapper {};\ninline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; }\ninline void  operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new()\n#define IM_ALLOC(_SIZE)                     ImGui::MemAlloc(_SIZE)\n#define IM_FREE(_PTR)                       ImGui::MemFree(_PTR)\n#define IM_PLACEMENT_NEW(_PTR)              new(ImNewWrapper(), _PTR)\n#define IM_NEW(_TYPE)                       new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE\ntemplate<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }\n\n//-----------------------------------------------------------------------------\n// ImVector<>\n// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).\n//-----------------------------------------------------------------------------\n// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it.\n// - We use std-like naming convention here, which is a little unusual for this codebase.\n// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.\n// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,\n//   Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.\n//-----------------------------------------------------------------------------\n\nIM_MSVC_RUNTIME_CHECKS_OFF\ntemplate<typename T>\nstruct ImVector\n{\n\tint                 Size;\n\tint                 Capacity;\n\tT* Data;\n\n\t// Provide standard typedefs but we don't use them ourselves.\n\ttypedef T                   value_type;\n\ttypedef value_type* iterator;\n\ttypedef const value_type* const_iterator;\n\n\t// Constructors, destructor\n\tinline ImVector() { Size = Capacity = 0; Data = NULL; }\n\tinline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }\n\tinline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }\n\tinline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything\n\n\tinline void         clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }  // Important: does not destruct anything\n\tinline void         clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); }     // Important: never called automatically! always explicit.\n\tinline void         clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); }           // Important: never called automatically! always explicit.\n\n\tinline bool         empty() const { return Size == 0; }\n\tinline int          size() const { return Size; }\n\tinline int          size_in_bytes() const { return Size * (int)sizeof(T); }\n\tinline int          max_size() const { return 0x7FFFFFFF / (int)sizeof(T); }\n\tinline int          capacity() const { return Capacity; }\n\tinline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }\n\tinline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }\n\n\tinline T* begin() { return Data; }\n\tinline const T* begin() const { return Data; }\n\tinline T* end() { return Data + Size; }\n\tinline const T* end() const { return Data + Size; }\n\tinline T& front() { IM_ASSERT(Size > 0); return Data[0]; }\n\tinline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; }\n\tinline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }\n\tinline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }\n\tinline void         swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }\n\n\tinline int          _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; }\n\tinline void         resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }\n\tinline void         resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }\n\tinline void         shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation\n\tinline void         reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }\n\tinline void         reserve_discard(int new_capacity) { if (new_capacity <= Capacity) return; if (Data) IM_FREE(Data); Data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); Capacity = new_capacity; }\n\n\t// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.\n\tinline void         push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }\n\tinline void         pop_back() { IM_ASSERT(Size > 0); Size--; }\n\tinline void         push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); }\n\tinline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; }\n\tinline T* erase(const T* it, const T* it_last) { IM_ASSERT(it >= Data && it < Data + Size && it_last >= it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); Size -= (int)count; return Data + off; }\n\tinline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size);  const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; }\n\tinline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }\n\tinline bool         contains(const T& v) const { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }\n\tinline T* find(const T& v) { T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }\n\tinline const T* find(const T& v) const { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }\n\tinline bool         find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; }\n\tinline bool         find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; }\n\tinline int          index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; }\n};\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiStyle\n//-----------------------------------------------------------------------------\n// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().\n// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,\n// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.\n//-----------------------------------------------------------------------------\n\nstruct ImGuiStyle\n{\n\tfloat       Alpha;                      // Global alpha applies to everything in Dear ImGui.\n\tfloat       DisabledAlpha;              // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.\n\tImVec2      WindowPadding;              // Padding within a window.\n\tfloat       WindowRounding;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.\n\tfloat       WindowBorderSize;           // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).\n\tImVec2      WindowMinSize;              // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints().\n\tImVec2      WindowTitleAlign;           // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.\n\tImGuiDir    WindowMenuButtonPosition;   // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left.\n\tfloat       ChildRounding;              // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.\n\tfloat       ChildBorderSize;            // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).\n\tfloat       PopupRounding;              // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)\n\tfloat       PopupBorderSize;            // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).\n\tImVec2      FramePadding;               // Padding within a framed rectangle (used by most widgets).\n\tfloat       FrameRounding;              // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets).\n\tfloat       FrameBorderSize;            // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).\n\tImVec2      ItemSpacing;                // Horizontal and vertical spacing between widgets/lines.\n\tImVec2      ItemInnerSpacing;           // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).\n\tImVec2      CellPadding;                // Padding within a table cell. CellPadding.y may be altered between different rows.\n\tImVec2      TouchExtraPadding;          // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!\n\tfloat       IndentSpacing;              // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).\n\tfloat       ColumnsMinSpacing;          // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).\n\tfloat       ScrollbarSize;              // Width of the vertical scrollbar, Height of the horizontal scrollbar.\n\tfloat       ScrollbarRounding;          // Radius of grab corners for scrollbar.\n\tfloat       GrabMinSize;                // Minimum width/height of a grab box for slider/scrollbar.\n\tfloat       GrabRounding;               // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.\n\tfloat       LogSliderDeadzone;          // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.\n\tfloat       TabRounding;                // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.\n\tfloat       TabBorderSize;              // Thickness of border around tabs.\n\tfloat       TabMinWidthForCloseButton;  // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.\n\tImGuiDir    ColorButtonPosition;        // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.\n\tImVec2      ButtonTextAlign;            // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).\n\tImVec2      SelectableTextAlign;        // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.\n\tfloat       SeparatorTextBorderSize;    // Thickkness of border in SeparatorText()\n\tImVec2      SeparatorTextAlign;         // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).\n\tImVec2      SeparatorTextPadding;       // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.\n\tImVec2      DisplayWindowPadding;       // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.\n\tImVec2      DisplaySafeAreaPadding;     // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!\n\tfloat       MouseCursorScale;           // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.\n\tbool        AntiAliasedLines;           // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).\n\tbool        AntiAliasedLinesUseTex;     // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList).\n\tbool        AntiAliasedFill;            // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).\n\tfloat       CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.\n\tfloat       CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.\n\tImVec4      Colors[ImGuiCol_COUNT];\n\n\t// Behaviors\n\t// (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields in ImGuiIO)\n\tfloat             HoverStationaryDelay;     // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.\n\tfloat             HoverDelayShort;          // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.\n\tfloat             HoverDelayNormal;         // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). \"\n\tImGuiHoveredFlags HoverFlagsForTooltipMouse;// Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.\n\tImGuiHoveredFlags HoverFlagsForTooltipNav;  // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.\n\n\tIMGUI_API ImGuiStyle();\n\tIMGUI_API void ScaleAllSizes(float scale_factor);\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiIO\n//-----------------------------------------------------------------------------\n// Communicate most settings and inputs/outputs to Dear ImGui using this structure.\n// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.\n//-----------------------------------------------------------------------------\n\n// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions.\n// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration.\nstruct ImGuiKeyData\n{\n\tbool        Down;               // True for if key is down\n\tfloat       DownDuration;       // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held)\n\tfloat       DownDurationPrev;   // Last frame duration the key has been down\n\tfloat       AnalogValue;        // 0.0f..1.0f for gamepad values\n};\n\nstruct ImGuiIO\n{\n\t//------------------------------------------------------------------\n\t// Configuration                            // Default value\n\t//------------------------------------------------------------------\n\n\tImGuiConfigFlags   ConfigFlags;             // = 0              // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.\n\tImGuiBackendFlags  BackendFlags;            // = 0              // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend.\n\tImVec2      DisplaySize;                    // <unset>          // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame.\n\tfloat       DeltaTime;                      // = 1.0f/60.0f     // Time elapsed since last frame, in seconds. May change every frame.\n\tfloat       IniSavingRate;                  // = 5.0f           // Minimum time between saving positions/sizes to .ini file, in seconds.\n\tconst char* IniFilename;                    // = \"imgui.ini\"    // Path to .ini file (important: default \"imgui.ini\" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions.\n\tconst char* LogFilename;                    // = \"imgui_log.txt\"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).\n\tvoid* UserData;                       // = NULL           // Store your own data.\n\n\tImFontAtlas* Fonts;                          // <auto>           // Font atlas: load, rasterize and pack one or more fonts into a single texture.\n\tfloat       FontGlobalScale;                // = 1.0f           // Global scale all fonts\n\tbool        FontAllowUserScaling;           // = false          // Allow user scaling text of individual window with CTRL+Wheel.\n\tImFont* FontDefault;                    // = NULL           // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].\n\tImVec2      DisplayFramebufferScale;        // = (1, 1)         // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale.\n\n\t// Miscellaneous options\n\tbool        MouseDrawCursor;                // = false          // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.\n\tbool        ConfigMacOSXBehaviors;          // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.\n\tbool        ConfigInputTrickleEventQueue;   // = true           // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.\n\tbool        ConfigInputTextCursorBlink;     // = true           // Enable blinking cursor (optional as some users consider it to be distracting).\n\tbool        ConfigInputTextEnterKeepActive; // = false          // [BETA] Pressing Enter will keep item active and select contents (single-line only).\n\tbool        ConfigDragClickToInputText;     // = false          // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard.\n\tbool        ConfigWindowsResizeFromEdges;   // = true           // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)\n\tbool        ConfigWindowsMoveFromTitleBarOnly; // = false       // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar.\n\tfloat       ConfigMemoryCompactTimer;       // = 60.0f          // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable.\n\n\t// Inputs Behaviors\n\t// (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle)\n\tfloat       MouseDoubleClickTime;           // = 0.30f          // Time for a double-click, in seconds.\n\tfloat       MouseDoubleClickMaxDist;        // = 6.0f           // Distance threshold to stay in to validate a double-click, in pixels.\n\tfloat       MouseDragThreshold;             // = 6.0f           // Distance threshold before considering we are dragging.\n\tfloat       KeyRepeatDelay;                 // = 0.275f         // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).\n\tfloat       KeyRepeatRate;                  // = 0.050f         // When holding a key/button, rate at which it repeats, in seconds.\n\n\t//------------------------------------------------------------------\n\t// Debug options\n\t//------------------------------------------------------------------\n\n\t// Tools to test correct Begin/End and BeginChild/EndChild behaviors.\n\t// Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()\n\t// This is inconsistent with other BeginXXX functions and create confusion for many users.\n\t// We expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code behavior.\n\tbool        ConfigDebugBeginReturnValueOnce;// = false          // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows.\n\tbool        ConfigDebugBeginReturnValueLoop;// = false          // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add \"io.ConfigDebugBeginReturnValue = io.KeyShift\" in your main loop then occasionally press SHIFT. Windows should be flickering while running.\n\n\t// Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.\n\t// Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them.\n\t// Consider using e.g. Win32's IsDebuggerPresent() as an additional filter (or see ImOsIsDebuggerPresent() in imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version).\n\tbool        ConfigDebugIgnoreFocusLoss;     // = false          // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing.\n\n\t// Options to audit .ini data\n\tbool        ConfigDebugIniSettings;         // = false          // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)\n\n\t//------------------------------------------------------------------\n\t// Platform Functions\n\t// (the imgui_impl_xxxx backend files are setting those up for you)\n\t//------------------------------------------------------------------\n\n\t// Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff.\n\tconst char* BackendPlatformName;            // = NULL\n\tconst char* BackendRendererName;            // = NULL\n\tvoid* BackendPlatformUserData;        // = NULL           // User data for platform backend\n\tvoid* BackendRendererUserData;        // = NULL           // User data for renderer backend\n\tvoid* BackendLanguageUserData;        // = NULL           // User data for non C++ programming language backend\n\n\t// Optional: Access OS clipboard\n\t// (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)\n\tconst char* (*GetClipboardTextFn)(void* user_data);\n\tvoid        (*SetClipboardTextFn)(void* user_data, const char* text);\n\tvoid* ClipboardUserData;\n\n\t// Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows)\n\t// (default to use native imm32 api on Windows)\n\tvoid        (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data);\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tvoid* ImeWindowHandle;                // = NULL           // [Obsolete] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning.\n#else\n\tvoid* _UnusedPadding;                                     // Unused field to keep data structure the same size.\n#endif\n\n\t// Optional: Platform locale\n\tImWchar     PlatformLocaleDecimalPoint;     // '.'              // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point\n\n\t//------------------------------------------------------------------\n\t// Input - Call before calling NewFrame()\n\t//------------------------------------------------------------------\n\n\t// Input Functions\n\tIMGUI_API void  AddKeyEvent(ImGuiKey key, bool down);                   // Queue a new key down/up event. Key should be \"translated\" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)\n\tIMGUI_API void  AddKeyAnalogEvent(ImGuiKey key, bool down, float v);    // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend.\n\tIMGUI_API void  AddMousePosEvent(float x, float y);                     // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered)\n\tIMGUI_API void  AddMouseButtonEvent(int button, bool down);             // Queue a mouse button change\n\tIMGUI_API void  AddMouseWheelEvent(float wheel_x, float wheel_y);       // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left.\n\tIMGUI_API void  AddMouseSourceEvent(ImGuiMouseSource source);           // Queue a mouse source change (Mouse/TouchScreen/Pen)\n\tIMGUI_API void  AddFocusEvent(bool focused);                            // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window)\n\tIMGUI_API void  AddInputCharacter(unsigned int c);                      // Queue a new character input\n\tIMGUI_API void  AddInputCharacterUTF16(ImWchar16 c);                    // Queue a new character input from a UTF-16 character, it can be a surrogate\n\tIMGUI_API void  AddInputCharactersUTF8(const char* str);                // Queue a new characters input from a UTF-8 string\n\n\tIMGUI_API void  SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode.\n\tIMGUI_API void  SetAppAcceptingEvents(bool accepting_events);           // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.\n\tIMGUI_API void  ClearEventsQueue();                                     // Clear all incoming events.\n\tIMGUI_API void  ClearInputKeys();                                       // Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tIMGUI_API void  ClearInputCharacters();                                 // [Obsolete] Clear the current frame text input buffer. Now included within ClearInputKeys().\n#endif\n\n\t//------------------------------------------------------------------\n\t// Output - Updated by NewFrame() or EndFrame()/Render()\n\t// (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is\n\t//  generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!)\n\t//------------------------------------------------------------------\n\n\tbool        WantCaptureMouse;                   // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.).\n\tbool        WantCaptureKeyboard;                // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).\n\tbool        WantTextInput;                      // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).\n\tbool        WantSetMousePos;                    // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.\n\tbool        WantSaveIniSettings;                // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving!\n\tbool        NavActive;                          // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.\n\tbool        NavVisible;                         // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events).\n\tfloat       Framerate;                          // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally.\n\tint         MetricsRenderVertices;              // Vertices output during last call to Render()\n\tint         MetricsRenderIndices;               // Indices output during last call to Render() = number of triangles * 3\n\tint         MetricsRenderWindows;               // Number of visible windows\n\tint         MetricsActiveWindows;               // Number of active windows\n\tint         MetricsActiveAllocations;           // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts.\n\tImVec2      MouseDelta;                         // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.\n\n\t// Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame.\n\t// This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent().\n\t//   Old (<1.87):  ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space)\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tint         KeyMap[ImGuiKey_COUNT];             // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your \"native\" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512.\n\tbool        KeysDown[ImGuiKey_COUNT];           // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the \"native\" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow.\n\tfloat       NavInputs[ImGuiNavInput_COUNT];     // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums.\n#endif\n\n\t//------------------------------------------------------------------\n\t// [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!\n\t//------------------------------------------------------------------\n\n\tImGuiContext* Ctx;                              // Parent UI context (needs to be set explicitly by parent).\n\n\t// Main Input State\n\t// (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead)\n\t// (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)\n\tImVec2      MousePos;                           // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)\n\tbool        MouseDown[5];                       // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.\n\tfloat       MouseWheel;                         // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll.\n\tfloat       MouseWheelH;                        // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.\n\tImGuiMouseSource MouseSource;                   // Mouse actual input peripheral (Mouse/TouchScreen/Pen).\n\tbool        KeyCtrl;                            // Keyboard modifier down: Control\n\tbool        KeyShift;                           // Keyboard modifier down: Shift\n\tbool        KeyAlt;                             // Keyboard modifier down: Alt\n\tbool        KeySuper;                           // Keyboard modifier down: Cmd/Super/Windows\n\n\t// Other state maintained from data above + IO function calls\n\tImGuiKeyChord KeyMods;                          // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame()\n\tImGuiKeyData  KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this.\n\tbool        WantCaptureMouseUnlessPopupClose;   // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup.\n\tImVec2      MousePosPrev;                       // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)\n\tImVec2      MouseClickedPos[5];                 // Position at time of clicking\n\tdouble      MouseClickedTime[5];                // Time of last click (used to figure out double-click)\n\tbool        MouseClicked[5];                    // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0)\n\tbool        MouseDoubleClicked[5];              // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2)\n\tImU16       MouseClickedCount[5];               // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down\n\tImU16       MouseClickedLastCount[5];           // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done.\n\tbool        MouseReleased[5];                   // Mouse button went from Down to !Down\n\tbool        MouseDownOwned[5];                  // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.\n\tbool        MouseDownOwnedUnlessPopupClose[5];  // Track if button was clicked inside a dear imgui window.\n\tbool        MouseWheelRequestAxisSwap;          // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.\n\tfloat       MouseDownDuration[5];               // Duration the mouse button has been down (0.0f == just clicked)\n\tfloat       MouseDownDurationPrev[5];           // Previous time the mouse button has been down\n\tfloat       MouseDragMaxDistanceSqr[5];         // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)\n\tfloat       PenPressure;                        // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui.\n\tbool        AppFocusLost;                       // Only modify via AddFocusEvent()\n\tbool        AppAcceptingEvents;                 // Only modify via SetAppAcceptingEvents()\n\tImS8        BackendUsingLegacyKeyArrays;        // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[]\n\tbool        BackendUsingLegacyNavInputArray;    // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly\n\tImWchar16   InputQueueSurrogate;                // For AddInputCharacterUTF16()\n\tImVector<ImWchar> InputQueueCharacters;         // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper.\n\n\tIMGUI_API   ImGuiIO();\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Misc data structures\n//-----------------------------------------------------------------------------\n\n// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.\n// The callback function should return 0 by default.\n// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details)\n// - ImGuiInputTextFlags_CallbackEdit:        Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)\n// - ImGuiInputTextFlags_CallbackAlways:      Callback on each iteration\n// - ImGuiInputTextFlags_CallbackCompletion:  Callback on pressing TAB\n// - ImGuiInputTextFlags_CallbackHistory:     Callback on pressing Up/Down arrows\n// - ImGuiInputTextFlags_CallbackCharFilter:  Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.\n// - ImGuiInputTextFlags_CallbackResize:      Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.\nstruct ImGuiInputTextCallbackData\n{\n\tImGuiContext* Ctx;            // Parent UI context\n\tImGuiInputTextFlags EventFlag;      // One ImGuiInputTextFlags_Callback*    // Read-only\n\tImGuiInputTextFlags Flags;          // What user passed to InputText()      // Read-only\n\tvoid* UserData;       // What user passed to InputText()      // Read-only\n\n\t// Arguments for the different callback events\n\t// - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary.\n\t// - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state.\n\tImWchar             EventChar;      // Character input                      // Read-write   // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0;\n\tImGuiKey            EventKey;       // Key pressed (Up/Down/TAB)            // Read-only    // [Completion,History]\n\tchar* Buf;            // Text buffer                          // Read-write   // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!\n\tint                 BufTextLen;     // Text length (in bytes)               // Read-write   // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length()\n\tint                 BufSize;        // Buffer size (in bytes) = capacity+1  // Read-only    // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1\n\tbool                BufDirty;       // Set if you modify Buf/BufTextLen!    // Write        // [Completion,History,Always]\n\tint                 CursorPos;      //                                      // Read-write   // [Completion,History,Always]\n\tint                 SelectionStart; //                                      // Read-write   // [Completion,History,Always] == to SelectionEnd when no selection)\n\tint                 SelectionEnd;   //                                      // Read-write   // [Completion,History,Always]\n\n\t// Helper functions for text manipulation.\n\t// Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection.\n\tIMGUI_API ImGuiInputTextCallbackData();\n\tIMGUI_API void      DeleteChars(int pos, int bytes_count);\n\tIMGUI_API void      InsertChars(int pos, const char* text, const char* text_end = NULL);\n\tvoid                SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; }\n\tvoid                ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; }\n\tbool                HasSelection() const { return SelectionStart != SelectionEnd; }\n};\n\n// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin().\n// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough.\nstruct ImGuiSizeCallbackData\n{\n\tvoid* UserData;       // Read-only.   What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>).\n\tImVec2  Pos;            // Read-only.   Window position, for reference.\n\tImVec2  CurrentSize;    // Read-only.   Current window size.\n\tImVec2  DesiredSize;    // Read-write.  Desired size, based on user's mouse position. Write to this field to restrain resizing.\n};\n\n// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()\nstruct ImGuiPayload\n{\n\t// Members\n\tvoid* Data;               // Data (copied and owned by dear imgui)\n\tint             DataSize;           // Data size\n\n\t// [Internal]\n\tImGuiID         SourceId;           // Source item id\n\tImGuiID         SourceParentId;     // Source parent id (if available)\n\tint             DataFrameCount;     // Data timestamp\n\tchar            DataType[32 + 1];   // Data type tag (short user-supplied string, 32 characters max)\n\tbool            Preview;            // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets)\n\tbool            Delivery;           // Set when AcceptDragDropPayload() was called and mouse button is released over the target item.\n\n\tImGuiPayload() { Clear(); }\n\tvoid Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; }\n\tbool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; }\n\tbool IsPreview() const { return Preview; }\n\tbool IsDelivery() const { return Delivery; }\n};\n\n// Sorting specification for one column of a table (sizeof == 12 bytes)\nstruct ImGuiTableColumnSortSpecs\n{\n\tImGuiID                     ColumnUserID;       // User id of the column (if specified by a TableSetupColumn() call)\n\tImS16                       ColumnIndex;        // Index of the column\n\tImS16                       SortOrder;          // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here)\n\tImGuiSortDirection          SortDirection : 8;  // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending (you can use this or SortSign, whichever is more convenient for your sort function)\n\n\tImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); }\n};\n\n// Sorting specifications for a table (often handling sort specs for a single column, occasionally more)\n// Obtained by calling TableGetSortSpecs().\n// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time.\n// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame!\nstruct ImGuiTableSortSpecs\n{\n\tconst ImGuiTableColumnSortSpecs* Specs;     // Pointer to sort spec array.\n\tint                         SpecsCount;     // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled.\n\tbool                        SpecsDirty;     // Set to true when specs have changed since last time! Use this to sort again, then clear the flag.\n\n\tImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)\n//-----------------------------------------------------------------------------\n\n// Helper: Unicode defines\n#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD     // Invalid Unicode code point (standard value).\n#ifdef IMGUI_USE_WCHAR32\n#define IM_UNICODE_CODEPOINT_MAX     0x10FFFF   // Maximum Unicode code point supported by this build.\n#else\n#define IM_UNICODE_CODEPOINT_MAX     0xFFFF     // Maximum Unicode code point supported by this build.\n#endif\n\n// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame.\n// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text(\"This will be called only once per frame\");\nstruct ImGuiOnceUponAFrame\n{\n\tImGuiOnceUponAFrame() { RefFrame = -1; }\n\tmutable int RefFrame;\n\toperator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }\n};\n\n// Helper: Parse and apply text filters. In format \"aaaaa[,bbbb][,ccccc]\"\nstruct ImGuiTextFilter\n{\n\tIMGUI_API           ImGuiTextFilter(const char* default_filter = \"\");\n\tIMGUI_API bool      Draw(const char* label = \"Filter (inc,-exc)\", float width = 0.0f);  // Helper calling InputText+Build\n\tIMGUI_API bool      PassFilter(const char* text, const char* text_end = NULL) const;\n\tIMGUI_API void      Build();\n\tvoid                Clear() { InputBuf[0] = 0; Build(); }\n\tbool                IsActive() const { return !Filters.empty(); }\n\n\t// [Internal]\n\tstruct ImGuiTextRange\n\t{\n\t\tconst char* b;\n\t\tconst char* e;\n\n\t\tImGuiTextRange() { b = e = NULL; }\n\t\tImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; }\n\t\tbool            empty() const { return b == e; }\n\t\tIMGUI_API void  split(char separator, ImVector<ImGuiTextRange>* out) const;\n\t};\n\tchar                    InputBuf[256];\n\tImVector<ImGuiTextRange>Filters;\n\tint                     CountGrep;\n};\n\n// Helper: Growable text buffer for logging/accumulating text\n// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder')\nstruct ImGuiTextBuffer\n{\n\tImVector<char>      Buf;\n\tIMGUI_API static char EmptyString[1];\n\n\tImGuiTextBuffer() { }\n\tinline char         operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }\n\tconst char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; }\n\tconst char* end() const { return Buf.Data ? &Buf.back() : EmptyString; }   // Buf is zero-terminated, so end() will point on the zero-terminator\n\tint                 size() const { return Buf.Size ? Buf.Size - 1 : 0; }\n\tbool                empty() const { return Buf.Size <= 1; }\n\tvoid                clear() { Buf.clear(); }\n\tvoid                reserve(int capacity) { Buf.reserve(capacity); }\n\tconst char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }\n\tIMGUI_API void      append(const char* str, const char* str_end = NULL);\n\tIMGUI_API void      appendf(const char* fmt, ...) IM_FMTARGS(2);\n\tIMGUI_API void      appendfv(const char* fmt, va_list args) IM_FMTLIST(2);\n};\n\n// Helper: Key->Value storage\n// Typically you don't have to worry about this since a storage is held within each Window.\n// We use it to e.g. store collapse state for a tree (Int 0/1)\n// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame)\n// You can use it as custom user storage for temporary values. Declare your own storage if, for example:\n// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state).\n// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient)\n// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types.\nstruct ImGuiStorage\n{\n\t// [Internal]\n\tstruct ImGuiStoragePair\n\t{\n\t\tImGuiID key;\n\t\tunion { int val_i; float val_f; void* val_p; };\n\t\tImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; }\n\t\tImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; }\n\t\tImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; }\n\t};\n\n\tImVector<ImGuiStoragePair>      Data;\n\n\t// - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)\n\t// - Set***() functions find pair, insertion on demand if missing.\n\t// - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair.\n\tvoid                Clear() { Data.clear(); }\n\tIMGUI_API int       GetInt(ImGuiID key, int default_val = 0) const;\n\tIMGUI_API void      SetInt(ImGuiID key, int val);\n\tIMGUI_API bool      GetBool(ImGuiID key, bool default_val = false) const;\n\tIMGUI_API void      SetBool(ImGuiID key, bool val);\n\tIMGUI_API float     GetFloat(ImGuiID key, float default_val = 0.0f) const;\n\tIMGUI_API void      SetFloat(ImGuiID key, float val);\n\tIMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL\n\tIMGUI_API void      SetVoidPtr(ImGuiID key, void* val);\n\n\t// - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set.\n\t// - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.\n\t// - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct)\n\t//      float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat(\"var\", pvar, 0, 100.0f); some_var += *pvar;\n\tIMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0);\n\tIMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false);\n\tIMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f);\n\tIMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL);\n\n\t// Use on your own storage if you know only integer are being stored (open/close all tree nodes)\n\tIMGUI_API void      SetAllInt(int val);\n\n\t// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.\n\tIMGUI_API void      BuildSortByKey();\n};\n\n// Helper: Manually clip large list of items.\n// If you have lots evenly spaced items and you have random access to the list, you can perform coarse\n// clipping based on visibility to only submit items that are in view.\n// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped.\n// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally\n//  fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily\n//  scale using lists with tens of thousands of items without a problem)\n// Usage:\n//   ImGuiListClipper clipper;\n//   clipper.Begin(1000);         // We have 1000 elements, evenly spaced.\n//   while (clipper.Step())\n//       for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)\n//           ImGui::Text(\"line number %d\", i);\n// Generally what happens is:\n// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not.\n// - User code submit that one element.\n// - Clipper can measure the height of the first element\n// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element.\n// - User code submit visible elements.\n// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc.\nstruct ImGuiListClipper\n{\n\tImGuiContext* Ctx;                // Parent UI context\n\tint             DisplayStart;       // First item to display, updated by each call to Step()\n\tint             DisplayEnd;         // End of items to display (exclusive)\n\tint             ItemsCount;         // [Internal] Number of items\n\tfloat           ItemsHeight;        // [Internal] Height of item after a first step and item submission can calculate it\n\tfloat           StartPosY;          // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed\n\tvoid* TempData;           // [Internal] Internal data\n\n\t// items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step)\n\t// items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().\n\tIMGUI_API ImGuiListClipper();\n\tIMGUI_API ~ImGuiListClipper();\n\tIMGUI_API void  Begin(int items_count, float items_height = -1.0f);\n\tIMGUI_API void  End();             // Automatically called on the last call of Step() that returns false.\n\tIMGUI_API bool  Step();            // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items.\n\n\t// Call IncludeItemByIndex() or IncludeItemsByIndex() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility.\n\t// (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range).\n\tinline void     IncludeItemByIndex(int item_index) { IncludeItemsByIndex(item_index, item_index + 1); }\n\tIMGUI_API void  IncludeItemsByIndex(int item_begin, int item_end);  // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped.\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tinline void IncludeRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.9]\n\tinline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6]\n\t//inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79]\n#endif\n};\n\n// Helpers: ImVec2/ImVec4 operators\n// - It is important that we are keeping those disabled by default so they don't leak in user space.\n// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h)\n// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy.\n#ifdef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED\nIM_MSVC_RUNTIME_CHECKS_OFF\nstatic inline ImVec2  operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }\nstatic inline ImVec2  operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }\nstatic inline ImVec2  operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }\nstatic inline ImVec2  operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }\nstatic inline ImVec2  operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }\nstatic inline ImVec2  operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }\nstatic inline ImVec2  operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); }\nstatic inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }\nstatic inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }\nstatic inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; }\nstatic inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }\nstatic inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; }\nstatic inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; }\nstatic inline ImVec4  operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }\nstatic inline ImVec4  operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }\nstatic inline ImVec4  operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n#endif\n\n// Helpers macros to generate 32-bit encoded colors\n// User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file.\n#ifndef IM_COL32_R_SHIFT\n#ifdef IMGUI_USE_BGRA_PACKED_COLOR\n#define IM_COL32_R_SHIFT    16\n#define IM_COL32_G_SHIFT    8\n#define IM_COL32_B_SHIFT    0\n#define IM_COL32_A_SHIFT    24\n#define IM_COL32_A_MASK     0xFF000000\n#else\n#define IM_COL32_R_SHIFT    0\n#define IM_COL32_G_SHIFT    8\n#define IM_COL32_B_SHIFT    16\n#define IM_COL32_A_SHIFT    24\n#define IM_COL32_A_MASK     0xFF000000\n#endif\n#endif\n#define IM_COL32(R,G,B,A)    (((ImU32)(A)<<IM_COL32_A_SHIFT) | ((ImU32)(B)<<IM_COL32_B_SHIFT) | ((ImU32)(G)<<IM_COL32_G_SHIFT) | ((ImU32)(R)<<IM_COL32_R_SHIFT))\n#define IM_COL32_WHITE       IM_COL32(255,255,255,255)  // Opaque white = 0xFFFFFFFF\n#define IM_COL32_BLACK       IM_COL32(0,0,0,255)        // Opaque black\n#define IM_COL32_BLACK_TRANS IM_COL32(0,0,0,0)          // Transparent black = 0x00000000\n\n// Helper: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)\n// Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API.\n// **Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. MAY OBSOLETE.\n// **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. Explicitly cast to ImU32 or ImVec4 if needed.\nstruct ImColor\n{\n\tImVec4          Value;\n\n\tconstexpr ImColor() { }\n\tconstexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { }\n\tconstexpr ImColor(const ImVec4& col) : Value(col) {}\n\tconstexpr ImColor(int r, int g, int b, int a = 255) : Value((float)r* (1.0f / 255.0f), (float)g* (1.0f / 255.0f), (float)b* (1.0f / 255.0f), (float)a* (1.0f / 255.0f)) {}\n\tconstexpr ImColor(ImU32 rgba) : Value((float)((rgba >> IM_COL32_R_SHIFT) & 0xFF)* (1.0f / 255.0f), (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF)* (1.0f / 255.0f), (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF)* (1.0f / 255.0f), (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF)* (1.0f / 255.0f)) {}\n\tinline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); }\n\tinline operator ImVec4() const { return Value; }\n\n\t// FIXME-OBSOLETE: May need to obsolete/cleanup those helpers.\n\tinline void    SetHSV(float h, float s, float v, float a = 1.0f) { ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; }\n\tstatic ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)\n// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.\n//-----------------------------------------------------------------------------\n\n// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking.\n#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX\n#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX     (63)\n#endif\n\n// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h]\n// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,\n// you can poke into the draw list for that! Draw callback may be useful for example to:\n//  A) Change your GPU render state,\n//  B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.\n// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'\n// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly.\n#ifndef ImDrawCallback\ntypedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);\n#endif\n\n// Special Draw callback value to request renderer backend to reset the graphics/render state.\n// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address.\n// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored.\n// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call).\n#define ImDrawCallback_ResetRenderState     (ImDrawCallback)(-1)\n\n// Typically, 1 command = 1 GPU draw call (unless command is a callback)\n// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled,\n//   this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices.\n//   Backends made for <1.71. will typically ignore the VtxOffset fields.\n// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for).\nstruct ImDrawCmd\n{\n\tImVec4          ClipRect;           // 4*4  // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in \"viewport\" coordinates\n\tImTextureID     TextureId;          // 4-8  // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.\n\tunsigned int    VtxOffset;          // 4    // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices.\n\tunsigned int    IdxOffset;          // 4    // Start offset in index buffer.\n\tunsigned int    ElemCount;          // 4    // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].\n\tImDrawCallback  UserCallback;       // 4-8  // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.\n\tvoid* UserCallbackData;   // 4-8  // The draw callback code can access this.\n\n\tImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed\n\n\t// Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature)\n\tinline ImTextureID GetTexID() const { return TextureId; }\n};\n\n// Vertex layout\n#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT\nstruct ImDrawVert\n{\n\tImVec2  pos;\n\tImVec2  uv;\n\tImU32   col;\n};\n#else\n// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h\n// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine.\n// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared at the time you'd want to set your type up.\n// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM.\nIMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT;\n#endif\n\n// [Internal] For use by ImDrawList\nstruct ImDrawCmdHeader\n{\n\tImVec4          ClipRect;\n\tImTextureID     TextureId;\n\tunsigned int    VtxOffset;\n};\n\n// [Internal] For use by ImDrawListSplitter\nstruct ImDrawChannel\n{\n\tImVector<ImDrawCmd>         _CmdBuffer;\n\tImVector<ImDrawIdx>         _IdxBuffer;\n};\n\n// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.\n// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call.\nstruct ImDrawListSplitter\n{\n\tint                         _Current;    // Current channel number (0)\n\tint                         _Count;      // Number of active channels (1+)\n\tImVector<ImDrawChannel>     _Channels;   // Draw channels (not resized down so _Count might be < Channels.Size)\n\n\tinline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); }\n\tinline ~ImDrawListSplitter() { ClearFreeMemory(); }\n\tinline void                 Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame\n\tIMGUI_API void              ClearFreeMemory();\n\tIMGUI_API void              Split(ImDrawList* draw_list, int count);\n\tIMGUI_API void              Merge(ImDrawList* draw_list);\n\tIMGUI_API void              SetCurrentChannel(ImDrawList* draw_list, int channel_idx);\n};\n\n// Flags for ImDrawList functions\n// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused)\nenum ImDrawFlags_\n{\n\tImDrawFlags_None = 0,\n\tImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason)\n\tImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01.\n\tImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02.\n\tImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04.\n\tImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08.\n\tImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag!\n\tImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight,\n\tImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,\n\tImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft,\n\tImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight,\n\tImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,\n\tImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified.\n\tImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone,\n};\n\n// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly.\n// It is however possible to temporarily alter flags between calls to ImDrawList:: functions.\nenum ImDrawListFlags_\n{\n\tImDrawListFlags_None = 0,\n\tImDrawListFlags_AntiAliasedLines = 1 << 0,  // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles)\n\tImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1,  // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).\n\tImDrawListFlags_AntiAliasedFill = 1 << 2,  // Enable anti-aliased edge around filled shapes (rounded rectangles, circles).\n\tImDrawListFlags_AllowVtxOffset = 1 << 3,  // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled.\n};\n\n// Draw command list\n// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame,\n// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.\n// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to\n// access the current window draw list and draw custom primitives.\n// You can interleave normal ImGui:: calls and adding primitives to the current draw list.\n// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize).\n// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!)\n// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects.\nstruct ImDrawList\n{\n\t// This is what you have to render\n\tImVector<ImDrawCmd>     CmdBuffer;          // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback.\n\tImVector<ImDrawIdx>     IdxBuffer;          // Index buffer. Each command consume ImDrawCmd::ElemCount of those\n\tImVector<ImDrawVert>    VtxBuffer;          // Vertex buffer.\n\tImDrawListFlags         Flags;              // Flags, you may poke into these to adjust anti-aliasing settings per-primitive.\n\n\t// [Internal, used while building lists]\n\tunsigned int            _VtxCurrentIdx;     // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0.\n\tImDrawListSharedData* _Data;              // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)\n\tconst char* _OwnerName;         // Pointer to owner window's name for debugging\n\tImDrawVert* _VtxWritePtr;       // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)\n\tImDrawIdx* _IdxWritePtr;       // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)\n\tImVector<ImVec4>        _ClipRectStack;     // [Internal]\n\tImVector<ImTextureID>   _TextureIdStack;    // [Internal]\n\tImVector<ImVec2>        _Path;              // [Internal] current path building\n\tImDrawCmdHeader         _CmdHeader;         // [Internal] template of active commands. Fields should match those of CmdBuffer.back().\n\tImDrawListSplitter      _Splitter;          // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)\n\tfloat                   _FringeScale;       // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content\n\n\t// If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)\n\tImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; }\n\n\t~ImDrawList() { _ClearFreeMemory(); }\n\tIMGUI_API void  PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect = false);  // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)\n\tIMGUI_API void  PushClipRectFullScreen();\n\tIMGUI_API void  PopClipRect();\n\tIMGUI_API void  PushTextureID(ImTextureID texture_id);\n\tIMGUI_API void  PopTextureID();\n\tinline ImVec2   GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); }\n\tinline ImVec2   GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); }\n\n\t// Primitives\n\t// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have \"inward\" anti-aliasing.\n\t// - For rectangular primitives, \"p_min\" and \"p_max\" represent the upper-left and lower-right corners.\n\t// - For circle primitives, use \"num_segments == 0\" to automatically calculate tessellation (preferred).\n\t//   In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12.\n\t//   In future versions we will use textures to provide cheaper and higher-quality circles.\n\t//   Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides.\n\tIMGUI_API void  AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f);\n\tIMGUI_API void  AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f);   // a: upper-left, b: lower-right (== upper-left + size)\n\tIMGUI_API void  AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0);                     // a: upper-left, b: lower-right (== upper-left + size)\n\tIMGUI_API void  AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);\n\tIMGUI_API void  AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f);\n\tIMGUI_API void  AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col);\n\tIMGUI_API void  AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f);\n\tIMGUI_API void  AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col);\n\tIMGUI_API void  AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f);\n\tIMGUI_API void  AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0);\n\tIMGUI_API void  AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f);\n\tIMGUI_API void  AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments);\n\tIMGUI_API void  AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);\n\tIMGUI_API void  AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);\n\tIMGUI_API void  AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);\n\tIMGUI_API void  AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);\n\tIMGUI_API void  AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points)\n\tIMGUI_API void  AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0);               // Quadratic Bezier (3 control points)\n\n\t// Image primitives\n\t// - Read FAQ to understand what ImTextureID is.\n\t// - \"p_min\" and \"p_max\" represent the upper-left and lower-right corners of the rectangle.\n\t// - \"uv_min\" and \"uv_max\" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture.\n\tIMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE);\n\tIMGUI_API void  AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE);\n\tIMGUI_API void  AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0);\n\n\t// Stateful path API, add points then finish with PathFillConvex() or PathStroke()\n\t// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have \"inward\" anti-aliasing.\n\tinline    void  PathClear() { _Path.Size = 0; }\n\tinline    void  PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }\n\tinline    void  PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); }\n\tinline    void  PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }\n\tinline    void  PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; }\n\tIMGUI_API void  PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0);\n\tIMGUI_API void  PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12);                // Use precomputed angles for a 12 steps circle\n\tIMGUI_API void  PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points)\n\tIMGUI_API void  PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0);               // Quadratic Bezier (3 control points)\n\tIMGUI_API void  PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0);\n\n\t// Advanced\n\tIMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.\n\tIMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible\n\tIMGUI_API ImDrawList* CloneOutput() const;                                  // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer.\n\n\t// Advanced: Channels\n\t// - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives)\n\t// - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end)\n\t// - This API shouldn't have been in ImDrawList in the first place!\n\t//   Prefer using your own persistent instance of ImDrawListSplitter as you can stack them.\n\t//   Using the ImDrawList::ChannelsXXXX you cannot stack a split over another.\n\tinline void     ChannelsSplit(int count) { _Splitter.Split(this, count); }\n\tinline void     ChannelsMerge() { _Splitter.Merge(this); }\n\tinline void     ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); }\n\n\t// Advanced: Primitives allocations\n\t// - We render triangles (three vertices)\n\t// - All primitives needs to be reserved via PrimReserve() beforehand.\n\tIMGUI_API void  PrimReserve(int idx_count, int vtx_count);\n\tIMGUI_API void  PrimUnreserve(int idx_count, int vtx_count);\n\tIMGUI_API void  PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col);      // Axis aligned rectangle (composed of two triangles)\n\tIMGUI_API void  PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col);\n\tIMGUI_API void  PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col);\n\tinline    void  PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; }\n\tinline    void  PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; }\n\tinline    void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index\n\n\t// Obsolete names\n\t//inline  void  AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021)\n\t//inline  void  PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021)\n\n\t// [Internal helpers]\n\tIMGUI_API void  _ResetForNewFrame();\n\tIMGUI_API void  _ClearFreeMemory();\n\tIMGUI_API void  _PopUnusedDrawCmd();\n\tIMGUI_API void  _TryMergeDrawCmds();\n\tIMGUI_API void  _OnChangedClipRect();\n\tIMGUI_API void  _OnChangedTextureID();\n\tIMGUI_API void  _OnChangedVtxOffset();\n\tIMGUI_API int   _CalcCircleAutoSegmentCount(float radius) const;\n\tIMGUI_API void  _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step);\n\tIMGUI_API void  _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments);\n};\n\n// All draw data to render a Dear ImGui frame\n// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose,\n// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList)\nstruct ImDrawData\n{\n\tbool                Valid;              // Only valid after Render() is called and before the next NewFrame() is called.\n\tint                 CmdListsCount;      // Number of ImDrawList* to render (should always be == CmdLists.size)\n\tint                 TotalIdxCount;      // For convenience, sum of all ImDrawList's IdxBuffer.Size\n\tint                 TotalVtxCount;      // For convenience, sum of all ImDrawList's VtxBuffer.Size\n\tImVector<ImDrawList*> CmdLists;         // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here.\n\tImVec2              DisplayPos;         // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications)\n\tImVec2              DisplaySize;        // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications)\n\tImVec2              FramebufferScale;   // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display.\n\tImGuiViewport* OwnerViewport;      // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not).\n\n\t// Functions\n\tImDrawData() { Clear(); }\n\tIMGUI_API void  Clear();\n\tIMGUI_API void  AddDrawList(ImDrawList* draw_list);     // Helper to add an external draw list into an existing ImDrawData.\n\tIMGUI_API void  DeIndexAllBuffers();                    // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!\n\tIMGUI_API void  ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)\n//-----------------------------------------------------------------------------\n\nstruct ImFontConfig\n{\n\tvoid* FontData;               //          // TTF/OTF data\n\tint             FontDataSize;           //          // TTF/OTF data size\n\tbool            FontDataOwnedByAtlas;   // true     // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).\n\tint             FontNo;                 // 0        // Index of font within TTF/OTF file\n\tfloat           SizePixels;             //          // Size in pixels for rasterizer (more or less maps to the resulting font height).\n\tint             OversampleH;            // 2        // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.\n\tint             OversampleV;            // 1        // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis.\n\tbool            PixelSnapH;             // false    // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.\n\tImVec2          GlyphExtraSpacing;      // 0, 0     // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.\n\tImVec2          GlyphOffset;            // 0, 0     // Offset all glyphs from this font input.\n\tconst ImWchar* GlyphRanges;            // NULL     // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).\n\tfloat           GlyphMinAdvanceX;       // 0        // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font\n\tfloat           GlyphMaxAdvanceX;       // FLT_MAX  // Maximum AdvanceX for glyphs\n\tbool            MergeMode;              // false    // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.\n\tunsigned int    FontBuilderFlags;       // 0        // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.\n\tfloat           RasterizerMultiply;     // 1.0f     // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable.\n\tImWchar         EllipsisChar;           // -1       // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.\n\n\t// [Internal]\n\tchar            Name[40];               // Name (strictly to ease debugging)\n\tImFont* DstFont;\n\n\tIMGUI_API ImFontConfig();\n};\n\n// Hold rendering data for one glyph.\n// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this)\nstruct ImFontGlyph\n{\n\tunsigned int    Colored : 1;        // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops)\n\tunsigned int    Visible : 1;        // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering.\n\tunsigned int    Codepoint : 30;     // 0x0000..0x10FFFF\n\tfloat           AdvanceX;           // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)\n\tfloat           X0, Y0, X1, Y1;     // Glyph corners\n\tfloat           U0, V0, U1, V1;     // Texture coordinates\n};\n\n// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges().\n// This is essentially a tightly packed of vector of 64k booleans = 8KB storage.\nstruct ImFontGlyphRangesBuilder\n{\n\tImVector<ImU32> UsedChars;            // Store 1-bit per Unicode code point (0=unused, 1=used)\n\n\tImFontGlyphRangesBuilder() { Clear(); }\n\tinline void     Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }\n\tinline bool     GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; }  // Get bit n in the array\n\tinline void     SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; }               // Set bit n in the array\n\tinline void     AddChar(ImWchar c) { SetBit(c); }                      // Add character\n\tIMGUI_API void  AddText(const char* text, const char* text_end = NULL);     // Add string (each character of the UTF-8 string are added)\n\tIMGUI_API void  AddRanges(const ImWchar* ranges);                           // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext\n\tIMGUI_API void  BuildRanges(ImVector<ImWchar>* out_ranges);                 // Output new ranges\n};\n\n// See ImFontAtlas::AddCustomRectXXX functions.\nstruct ImFontAtlasCustomRect\n{\n\tunsigned short  Width, Height;  // Input    // Desired rectangle dimension\n\tunsigned short  X, Y;           // Output   // Packed position in Atlas\n\tunsigned int    GlyphID;        // Input    // For custom font glyphs only (ID < 0x110000)\n\tfloat           GlyphAdvanceX;  // Input    // For custom font glyphs only: glyph xadvance\n\tImVec2          GlyphOffset;    // Input    // For custom font glyphs only: glyph display offset\n\tImFont* Font;           // Input    // For custom font glyphs only: target font\n\tImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; }\n\tbool IsPacked() const { return X != 0xFFFF; }\n};\n\n// Flags for ImFontAtlas build\nenum ImFontAtlasFlags_\n{\n\tImFontAtlasFlags_None = 0,\n\tImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0,   // Don't round the height to next power of two\n\tImFontAtlasFlags_NoMouseCursors = 1 << 1,   // Don't build software mouse cursors into the atlas (save a little texture memory)\n\tImFontAtlasFlags_NoBakedLines = 1 << 2,   // Don't build thick line textures into the atlas (save a little texture memory, allow support for point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU).\n};\n\n// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding:\n//  - One or more fonts.\n//  - Custom graphics data needed to render the shapes needed by Dear ImGui.\n//  - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas).\n// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api.\n//  - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you.\n//  - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.\n//  - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples)\n//  - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.\n//    This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details.\n// Common pitfalls:\n// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the\n//   atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.\n// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction.\n//   You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed,\n// - Even though many functions are suffixed with \"TTF\", OTF data is supported just as well.\n// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the future!\nstruct ImFontAtlas\n{\n\tIMGUI_API ImFontAtlas();\n\tIMGUI_API ~ImFontAtlas();\n\tIMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg);\n\tIMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL);\n\tIMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);\n\tIMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed.\n\tIMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.\n\tIMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);              // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.\n\tIMGUI_API void              ClearInputData();           // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.\n\tIMGUI_API void              ClearTexData();             // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory.\n\tIMGUI_API void              ClearFonts();               // Clear output font data (glyphs storage, UV coordinates).\n\tIMGUI_API void              Clear();                    // Clear all input and output.\n\n\t// Build atlas, retrieve pixel data.\n\t// User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().\n\t// The pitch is always = Width * BytesPerPixels (1 or 4)\n\t// Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into\n\t// the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste.\n\tIMGUI_API bool              Build();                    // Build pixels data. This is called automatically for you by the GetTexData*** functions.\n\tIMGUI_API void              GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 1 byte per-pixel\n\tIMGUI_API void              GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 4 bytes-per-pixel\n\tbool                        IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent...\n\tvoid                        SetTexID(ImTextureID id) { TexID = id; }\n\n\t//-------------------------------------------\n\t// Glyph Ranges\n\t//-------------------------------------------\n\n\t// Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)\n\t// NB: Make sure that your string are UTF-8 and NOT in your local code page.\n\t// Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details.\n\t// NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data.\n\tIMGUI_API const ImWchar* GetGlyphRangesDefault();                // Basic Latin, Extended Latin\n\tIMGUI_API const ImWchar* GetGlyphRangesGreek();                  // Default + Greek and Coptic\n\tIMGUI_API const ImWchar* GetGlyphRangesKorean();                 // Default + Korean characters\n\tIMGUI_API const ImWchar* GetGlyphRangesJapanese();               // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs\n\tIMGUI_API const ImWchar* GetGlyphRangesChineseFull();            // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs\n\tIMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese\n\tIMGUI_API const ImWchar* GetGlyphRangesCyrillic();               // Default + about 400 Cyrillic characters\n\tIMGUI_API const ImWchar* GetGlyphRangesThai();                   // Default + Thai characters\n\tIMGUI_API const ImWchar* GetGlyphRangesVietnamese();             // Default + Vietnamese characters\n\n\t//-------------------------------------------\n\t// [BETA] Custom Rectangles/Glyphs API\n\t//-------------------------------------------\n\n\t// You can request arbitrary rectangles to be packed into the atlas, for your own purposes.\n\t// - After calling Build(), you can query the rectangle position and render your pixels.\n\t// - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of prefered texture format.\n\t// - You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),\n\t//   so you can render e.g. custom colorful icons and use them as regular glyphs.\n\t// - Read docs/FONTS.md for more details about using colorful icons.\n\t// - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings.\n\tIMGUI_API int               AddCustomRectRegular(int width, int height);\n\tIMGUI_API int               AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0));\n\tImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; }\n\n\t// [Internal]\n\tIMGUI_API void              CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const;\n\tIMGUI_API bool              GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);\n\n\t//-------------------------------------------\n\t// Members\n\t//-------------------------------------------\n\n\tImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)\n\tImTextureID                 TexID;              // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.\n\tint                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.\n\tint                         TexGlyphPadding;    // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false).\n\tbool                        Locked;             // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.\n\tvoid* UserData;           // Store your own atlas related user-data (if e.g. you have multiple font atlas).\n\n\t// [Internal]\n\t// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.\n\tbool                        TexReady;           // Set when texture was built matching current font input\n\tbool                        TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format.\n\tunsigned char* TexPixelsAlpha8;    // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight\n\tunsigned int* TexPixelsRGBA32;    // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4\n\tint                         TexWidth;           // Texture width calculated during Build().\n\tint                         TexHeight;          // Texture height calculated during Build().\n\tImVec2                      TexUvScale;         // = (1.0f/TexWidth, 1.0f/TexHeight)\n\tImVec2                      TexUvWhitePixel;    // Texture coordinates to a white pixel\n\tImVector<ImFont*>           Fonts;              // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.\n\tImVector<ImFontAtlasCustomRect> CustomRects;    // Rectangles for packing custom texture data into the atlas.\n\tImVector<ImFontConfig>      ConfigData;         // Configuration data\n\tImVec4                      TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1];  // UVs for baked anti-aliased lines\n\n\t// [Internal] Font builder\n\tconst ImFontBuilderIO* FontBuilderIO;      // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE).\n\tunsigned int                FontBuilderFlags;   // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig.\n\n\t// [Internal] Packing data\n\tint                         PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors\n\tint                         PackIdLines;        // Custom texture rectangle ID for baked anti-aliased lines\n\n\t// [Obsolete]\n\t//typedef ImFontAtlasCustomRect    CustomRect;         // OBSOLETED in 1.72+\n\t//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+\n};\n\n// Font runtime data and rendering\n// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32().\nstruct ImFont\n{\n\t// Members: Hot ~20/24 bytes (for CalcTextSize)\n\tImVector<float>             IndexAdvanceX;      // 12-16 // out //            // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI).\n\tfloat                       FallbackAdvanceX;   // 4     // out // = FallbackGlyph->AdvanceX\n\tfloat                       FontSize;           // 4     // in  //            // Height of characters/line, set during loading (don't change after loading)\n\n\t// Members: Hot ~28/40 bytes (for CalcTextSize + render loop)\n\tImVector<ImWchar>           IndexLookup;        // 12-16 // out //            // Sparse. Index glyphs by Unicode code-point.\n\tImVector<ImFontGlyph>       Glyphs;             // 12-16 // out //            // All glyphs.\n\tconst ImFontGlyph* FallbackGlyph;      // 4-8   // out // = FindGlyph(FontFallbackChar)\n\n\t// Members: Cold ~32/40 bytes\n\tImFontAtlas* ContainerAtlas;     // 4-8   // out //            // What we has been loaded into\n\tconst ImFontConfig* ConfigData;         // 4-8   // in  //            // Pointer within ContainerAtlas->ConfigData\n\tshort                       ConfigDataCount;    // 2     // in  // ~ 1        // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.\n\tImWchar                     FallbackChar;       // 2     // out // = FFFD/'?' // Character used if a glyph isn't found.\n\tImWchar                     EllipsisChar;       // 2     // out // = '...'/'.'// Character used for ellipsis rendering.\n\tshort                       EllipsisCharCount;  // 1     // out // 1 or 3\n\tfloat                       EllipsisWidth;      // 4     // out               // Width\n\tfloat                       EllipsisCharStep;   // 4     // out               // Step between characters when EllipsisCount > 0\n\tbool                        DirtyLookupTables;  // 1     // out //\n\tfloat                       Scale;              // 4     // in  // = 1.f      // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()\n\tfloat                       Ascent, Descent;    // 4+4   // out //            // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]\n\tint                         MetricsTotalSurface;// 4     // out //            // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)\n\tImU8                        Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX + 1) / 4096 / 8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.\n\n\t// Methods\n\tIMGUI_API ImFont();\n\tIMGUI_API ~ImFont();\n\tIMGUI_API const ImFontGlyph* FindGlyph(ImWchar c) const;\n\tIMGUI_API const ImFontGlyph* FindGlyphNoFallback(ImWchar c) const;\n\tfloat                       GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }\n\tbool                        IsLoaded() const { return ContainerAtlas != NULL; }\n\tconst char* GetDebugName() const { return ConfigData ? ConfigData->Name : \"<unknown>\"; }\n\n\t// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.\n\t// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.\n\tIMGUI_API ImVec2            CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8\n\tIMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const;\n\tIMGUI_API void              RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const;\n\tIMGUI_API void              RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const;\n\n\t// [Internal] Don't use!\n\tIMGUI_API void              BuildLookupTable();\n\tIMGUI_API void              ClearOutputData();\n\tIMGUI_API void              GrowIndex(int new_size);\n\tIMGUI_API void              AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);\n\tIMGUI_API void              AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.\n\tIMGUI_API void              SetGlyphVisible(ImWchar c, bool visible);\n\tIMGUI_API bool              IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Viewports\n//-----------------------------------------------------------------------------\n\n// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends.\nenum ImGuiViewportFlags_\n{\n\tImGuiViewportFlags_None = 0,\n\tImGuiViewportFlags_IsPlatformWindow = 1 << 0,   // Represent a Platform Window\n\tImGuiViewportFlags_IsPlatformMonitor = 1 << 1,   // Represent a Platform Monitor (unused yet)\n\tImGuiViewportFlags_OwnedByApp = 1 << 2,   // Platform Window: is created/managed by the application (rather than a dear imgui backend)\n};\n\n// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows.\n// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports.\n// - In the future we will extend this concept further to also represent Platform Monitor and support a \"no main platform window\" operation mode.\n// - About Main Area vs Work Area:\n//   - Main Area = entire viewport.\n//   - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor).\n//   - Windows are generally trying to stay within the Work Area of their host viewport.\nstruct ImGuiViewport\n{\n\tImGuiViewportFlags  Flags;                  // See ImGuiViewportFlags_\n\tImVec2              Pos;                    // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates)\n\tImVec2              Size;                   // Main Area: Size of the viewport.\n\tImVec2              WorkPos;                // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos)\n\tImVec2              WorkSize;               // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size)\n\n\t// Platform/Backend Dependent Data\n\tvoid* PlatformHandleRaw;      // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms)\n\n\tImGuiViewport() { memset(this, 0, sizeof(*this)); }\n\n\t// Helpers\n\tImVec2              GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }\n\tImVec2              GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Platform Dependent Interfaces\n//-----------------------------------------------------------------------------\n\n// (Optional) Support for IME (Input Method Editor) via the io.SetPlatformImeDataFn() function.\nstruct ImGuiPlatformImeData\n{\n\tbool    WantVisible;        // A widget wants the IME to be visible\n\tImVec2  InputPos;           // Position of the input cursor\n\tfloat   InputLineHeight;    // Line height\n\n\tImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Obsolete functions and types\n// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details)\n// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead.\n//-----------------------------------------------------------------------------\n\nnamespace ImGui\n{\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tIMGUI_API ImGuiKey     GetKeyIndex(ImGuiKey key);  // map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]\n#else\n\tstatic inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END && \"ImGuiKey and native_index was merged together and native_index is disabled by IMGUI_DISABLE_OBSOLETE_KEYIO. Please switch to ImGuiKey.\"); return key; }\n#endif\n}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\nnamespace ImGui\n{\n\t// OBSOLETED in 1.89.7 (from June 2023)\n\tIMGUI_API void      SetItemAllowOverlap();                                              // Use SetNextItemAllowOverlap() before item.\n\t// OBSOLETED in 1.89.4 (from March 2023)\n\tstatic inline void  PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); }\n\tstatic inline void  PopAllowKeyboardFocus() { PopTabStop(); }\n\t// OBSOLETED in 1.89 (from August 2022)\n\tIMGUI_API bool      ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding)\n\t// OBSOLETED in 1.88 (from May 2022)\n\tstatic inline void  CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value.\n\tstatic inline void  CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); }       // Renamed as name was misleading + removed default value.\n\t// OBSOLETED in 1.86 (from November 2021)\n\tIMGUI_API void      CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Calculate coarse clipping for large list of evenly sized items. Prefer using ImGuiListClipper.\n\t// OBSOLETED in 1.85 (from August 2021)\n\tstatic inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; }\n\n\t// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)\n\t//-- OBSOLETED in 1.81 (from February 2021)\n\t//static inline bool  ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0))         { return BeginListBox(label, size); }\n\t//static inline bool  ListBoxHeader(const char* label, int items_count, int height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } // Helper to calculate size from items_count and height_in_items\n\t//static inline void  ListBoxFooter()                                                             { EndListBox(); }\n\t//-- OBSOLETED in 1.79 (from August 2020)\n\t//static inline void  OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1)    { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry!\n\t//-- OBSOLETED in 1.78 (from June 2020): Old drag/sliders functions that took a 'float power > 1.0f' argument instead of ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details.\n\t//IMGUI_API bool      DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f)                                                            // OBSOLETED in 1.78 (from June 2020)\n\t//IMGUI_API bool      DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f);                                          // OBSOLETED in 1.78 (from June 2020)\n\t//IMGUI_API bool      SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power = 1.0f);                                                                        // OBSOLETED in 1.78 (from June 2020)\n\t//IMGUI_API bool      SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power = 1.0f);                                                       // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power = 1.0f)    { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); }     // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power = 1.0f)                 { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); }            // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power = 1.0f)              { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); }        // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power = 1.0f)              { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); }        // OBSOLETED in 1.78 (from June 2020)\n\t//static inline bool  SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power = 1.0f)              { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); }        // OBSOLETED in 1.78 (from June 2020)\n\t//-- OBSOLETED in 1.77 and before\n\t//static inline bool  BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } // OBSOLETED in 1.77 (from June 2020)\n\t//static inline void  TreeAdvanceToLabelPos()               { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); }   // OBSOLETED in 1.72 (from July 2019)\n\t//static inline void  SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }                       // OBSOLETED in 1.71 (from June 2019)\n\t//static inline float GetContentRegionAvailWidth()          { return GetContentRegionAvail().x; }                               // OBSOLETED in 1.70 (from May 2019)\n\t//static inline ImDrawList* GetOverlayDrawList()            { return GetForegroundDrawList(); }                                 // OBSOLETED in 1.69 (from Mar 2019)\n\t//static inline void  SetScrollHere(float ratio = 0.5f)     { SetScrollHereY(ratio); }                                          // OBSOLETED in 1.66 (from Nov 2018)\n\t//static inline bool  IsItemDeactivatedAfterChange()        { return IsItemDeactivatedAfterEdit(); }                            // OBSOLETED in 1.63 (from Aug 2018)\n\t//-- OBSOLETED in 1.60 and before\n\t//static inline bool  IsAnyWindowFocused()                  { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); }            // OBSOLETED in 1.60 (from Apr 2018)\n\t//static inline bool  IsAnyWindowHovered()                  { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }            // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018)\n\t//static inline void  ShowTestWindow()                      { return ShowDemoWindow(); }                                        // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)\n\t//static inline bool  IsRootWindowFocused()                 { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); }           // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)\n\t//static inline bool  IsRootWindowOrAnyChildFocused()       { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); }  // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)\n\t//static inline void  SetNextWindowContentWidth(float w)    { SetNextWindowContentSize(ImVec2(w, 0.0f)); }                      // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)\n\t//static inline float GetItemsLineHeightWithSpacing()       { return GetFrameHeightWithSpacing(); }                             // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)\n\t//IMGUI_API bool      Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha().\n\t//static inline bool  IsRootWindowOrAnyChildHovered()       { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); }  // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)\n\t//static inline void  AlignFirstTextHeightToWidgets()       { AlignTextToFramePadding(); }                                      // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)\n\t//static inline void  SetNextWindowPosCenter(ImGuiCond c=0) { SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)\n\t//static inline bool  IsItemHoveredRect()                   { return IsItemHovered(ImGuiHoveredFlags_RectOnly); }               // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)\n\t//static inline bool  IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; }                                     // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the io.WantCaptureMouse flag instead.\n\t//static inline bool  IsMouseHoveringAnyWindow()            { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }            // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)\n\t//static inline bool  IsMouseHoveringWindow()               { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); }       // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)\n\t//-- OBSOLETED in 1.50 and before\n\t//static inline bool  CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49\n\t//static inline ImFont*GetWindowFont()                      { return GetFont(); }                                               // OBSOLETED in 1.48\n\t//static inline float GetWindowFontSize()                   { return GetFontSize(); }                                           // OBSOLETED in 1.48\n\t//static inline void  SetScrollPosHere()                    { SetScrollHere(); }                                                // OBSOLETED in 1.42\n}\n\n// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect()\ntypedef ImDrawFlags ImDrawCornerFlags;\nenum ImDrawCornerFlags_\n{\n\tImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone,         // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit\n\tImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft,      // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally).\n\tImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight,     // Was == 0x02 (1 << 1) prior to 1.82.\n\tImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft,   // Was == 0x04 (1 << 2) prior to 1.82.\n\tImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight,  // Was == 0x08 (1 << 3) prior to 1.82.\n\tImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll,          // Was == 0x0F prior to 1.82\n\tImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight,\n\tImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight,\n\tImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft,\n\tImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight,\n};\n\n// RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022)\n// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of obscolescence schedule to reduce confusion and because they were not meant to be used in the first place.\ntypedef ImGuiKeyChord ImGuiModFlags;      // == int. We generally use ImGuiKeyChord to mean \"a ImGuiKey or-ed with any number of ImGuiMod_XXX value\", but you may store only mods in there.\nenum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super };\n//typedef ImGuiKeyChord ImGuiKeyModFlags; // == int\n//enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super };\n\n#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\n// RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022)\n#if defined(IMGUI_DISABLE_METRICS_WINDOW) && !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS)\n#define IMGUI_DISABLE_DEBUG_TOOLS\n#endif\n#if defined(IMGUI_DISABLE_METRICS_WINDOW) && defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS)\n#error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name.\n#endif\n\n//-----------------------------------------------------------------------------\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#elif defined(__GNUC__)\n#pragma GCC diagnostic pop\n#endif\n\n#ifdef _MSC_VER\n#pragma warning (pop)\n#endif\n\n// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h)\n#ifdef IMGUI_INCLUDE_IMGUI_USER_H\n#include \"imgui_user.h\"\n#endif\n\n#endif // #ifndef IMGUI_DISABLE\n"
  },
  {
    "path": "KBotExt/imgui/imgui_draw.cpp",
    "content": "// dear imgui, v1.89.9\n// (drawing and font code)\n\n/*\n\nIndex of this file:\n\n// [SECTION] STB libraries implementation\n// [SECTION] Style functions\n// [SECTION] ImDrawList\n// [SECTION] ImDrawListSplitter\n// [SECTION] ImDrawData\n// [SECTION] Helpers ShadeVertsXXX functions\n// [SECTION] ImFontConfig\n// [SECTION] ImFontAtlas\n// [SECTION] ImFontAtlas glyph ranges helpers\n// [SECTION] ImFontGlyphRangesBuilder\n// [SECTION] ImFont\n// [SECTION] ImGui Internal Render Helpers\n// [SECTION] Decompression code\n// [SECTION] Default font data (ProggyClean.ttf)\n\n*/\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#ifndef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS\n#endif\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_internal.h\"\n#ifdef IMGUI_ENABLE_FREETYPE\n#include \"imgui_freetype.h\"\n#endif\n\n#include <stdio.h>      // vsnprintf, sscanf, printf\n\n// Visual Studio warnings\n#ifdef _MSC_VER\n#pragma warning (disable: 4127)     // condition expression is constant\n#pragma warning (disable: 4505)     // unreferenced local function has been removed (stb stuff)\n#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen\n#pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).\n#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)\n#endif\n\n// Clang/GCC warnings with -Weverything\n#if defined(__clang__)\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wold-style-cast\"                 // warning: use of old-style cast                            // yes, they are more terse.\n#pragma clang diagnostic ignored \"-Wfloat-equal\"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok.\n#pragma clang diagnostic ignored \"-Wglobal-constructors\"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.\n#pragma clang diagnostic ignored \"-Wsign-conversion\"                // warning: implicit conversion changes signedness\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0\n#pragma clang diagnostic ignored \"-Wcomma\"                          // warning: possible misuse of comma operator here\n#pragma clang diagnostic ignored \"-Wreserved-id-macro\"              // warning: macro name is a reserved identifier\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.\n#pragma clang diagnostic ignored \"-Wimplicit-int-float-conversion\"  // warning: implicit conversion from 'xxx' to 'float' may lose precision\n#pragma clang diagnostic ignored \"-Wreserved-identifier\"            // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter\n#elif defined(__GNUC__)\n#pragma GCC diagnostic ignored \"-Wpragmas\"                  // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wunused-function\"          // warning: 'xxxx' defined but not used\n#pragma GCC diagnostic ignored \"-Wdouble-promotion\"         // warning: implicit conversion from 'float' to 'double' when passing argument to function\n#pragma GCC diagnostic ignored \"-Wconversion\"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value\n#pragma GCC diagnostic ignored \"-Wstack-protector\"          // warning: stack protector not protecting local variables: variable length buffer\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"          // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#endif\n\n//-------------------------------------------------------------------------\n// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack)\n//-------------------------------------------------------------------------\n\n// Compile time options:\n//#define IMGUI_STB_NAMESPACE           ImStb\n//#define IMGUI_STB_TRUETYPE_FILENAME   \"my_folder/stb_truetype.h\"\n//#define IMGUI_STB_RECT_PACK_FILENAME  \"my_folder/stb_rect_pack.h\"\n//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION\n//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION\n\n#ifdef IMGUI_STB_NAMESPACE\nnamespace IMGUI_STB_NAMESPACE\n{\n#endif\n\n#ifdef _MSC_VER\n#pragma warning (push)\n#pragma warning (disable: 4456)                             // declaration of 'xx' hides previous local declaration\n#pragma warning (disable: 6011)                             // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.\n#pragma warning (disable: 6385)                             // (stb_truetype) Reading invalid data from 'buffer':  the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read.\n#pragma warning (disable: 28182)                            // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did.\n#endif\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#pragma clang diagnostic ignored \"-Wmissing-prototypes\"\n#pragma clang diagnostic ignored \"-Wimplicit-fallthrough\"\n#pragma clang diagnostic ignored \"-Wcast-qual\"              // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier\n#endif\n\n#if defined(__GNUC__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wtype-limits\"              // warning: comparison is always true due to limited range of data type [-Wtype-limits]\n#pragma GCC diagnostic ignored \"-Wcast-qual\"                // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers\n#endif\n\n#ifndef STB_RECT_PACK_IMPLEMENTATION                        // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)\n#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION          // in case the user already have an implementation in another compilation unit\n#define STBRP_STATIC\n#define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)\n#define STBRP_SORT          ImQsort\n#define STB_RECT_PACK_IMPLEMENTATION\n#endif\n#ifdef IMGUI_STB_RECT_PACK_FILENAME\n#include IMGUI_STB_RECT_PACK_FILENAME\n#else\n#include \"imstb_rectpack.h\"\n#endif\n#endif\n\n#ifdef  IMGUI_ENABLE_STB_TRUETYPE\n#ifndef STB_TRUETYPE_IMPLEMENTATION                         // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)\n#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION           // in case the user already have an implementation in another compilation unit\n#define STBTT_malloc(x,u)   ((void)(u), IM_ALLOC(x))\n#define STBTT_free(x,u)     ((void)(u), IM_FREE(x))\n#define STBTT_assert(x)     do { IM_ASSERT(x); } while(0)\n#define STBTT_fmod(x,y)     ImFmod(x,y)\n#define STBTT_sqrt(x)       ImSqrt(x)\n#define STBTT_pow(x,y)      ImPow(x,y)\n#define STBTT_fabs(x)       ImFabs(x)\n#define STBTT_ifloor(x)     ((int)ImFloorSigned(x))\n#define STBTT_iceil(x)      ((int)ImCeil(x))\n#define STBTT_STATIC\n#define STB_TRUETYPE_IMPLEMENTATION\n#else\n#define STBTT_DEF extern\n#endif\n#ifdef IMGUI_STB_TRUETYPE_FILENAME\n#include IMGUI_STB_TRUETYPE_FILENAME\n#else\n#include \"imstb_truetype.h\"\n#endif\n#endif\n#endif // IMGUI_ENABLE_STB_TRUETYPE\n\n#if defined(__GNUC__)\n#pragma GCC diagnostic pop\n#endif\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n#if defined(_MSC_VER)\n#pragma warning (pop)\n#endif\n\n#ifdef IMGUI_STB_NAMESPACE\n} // namespace ImStb\nusing namespace IMGUI_STB_NAMESPACE;\n#endif\n\n//-----------------------------------------------------------------------------\n// [SECTION] Style functions\n//-----------------------------------------------------------------------------\n\nvoid ImGui::StyleColorsDark(ImGuiStyle* dst)\n{\n\tImGuiStyle* style = dst ? dst : &ImGui::GetStyle();\n\tImVec4* colors = style->Colors;\n\n\tcolors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);\n\tcolors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);\n\tcolors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);\n\tcolors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);\n\tcolors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);\n\tcolors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);\n\tcolors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);\n\tcolors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);\n\tcolors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);\n\tcolors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);\n\tcolors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);\n\tcolors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);\n\tcolors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);\n\tcolors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);\n\tcolors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);\n\tcolors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);\n\tcolors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);\n\tcolors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);\n\tcolors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);\n\tcolors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_Separator] = colors[ImGuiCol_Border];\n\tcolors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);\n\tcolors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);\n\tcolors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);\n\tcolors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);\n\tcolors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);\n\tcolors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);\n\tcolors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];\n\tcolors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);\n\tcolors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);\n\tcolors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);\n\tcolors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);\n\tcolors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);\n\tcolors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);\n\tcolors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);\n\tcolors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);\n\tcolors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);\n\tcolors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);\n\tcolors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);\n}\n\nvoid ImGui::StyleColorsClassic(ImGuiStyle* dst)\n{\n\tImGuiStyle* style = dst ? dst : &ImGui::GetStyle();\n\tImVec4* colors = style->Colors;\n\n\tcolors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);\n\tcolors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);\n\tcolors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);\n\tcolors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);\n\tcolors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);\n\tcolors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);\n\tcolors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);\n\tcolors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);\n\tcolors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);\n\tcolors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);\n\tcolors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);\n\tcolors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);\n\tcolors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);\n\tcolors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);\n\tcolors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);\n\tcolors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);\n\tcolors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);\n\tcolors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);\n\tcolors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);\n\tcolors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);\n\tcolors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);\n\tcolors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);\n\tcolors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);\n\tcolors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);\n\tcolors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);\n\tcolors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);\n\tcolors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);\n\tcolors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);\n\tcolors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);\n\tcolors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);\n\tcolors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);\n\tcolors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);\n\tcolors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];\n\tcolors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);\n\tcolors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);\n\tcolors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);\n\tcolors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f);\n\tcolors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);\n\tcolors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);\n\tcolors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);\n\tcolors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];\n\tcolors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);\n\tcolors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);\n\tcolors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);\n}\n\n// Those light colors are better suited with a thicker font than the default one + FrameBorder\nvoid ImGui::StyleColorsLight(ImGuiStyle* dst)\n{\n\tImGuiStyle* style = dst ? dst : &ImGui::GetStyle();\n\tImVec4* colors = style->Colors;\n\n\tcolors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);\n\tcolors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);\n\tcolors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);\n\tcolors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);\n\tcolors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);\n\tcolors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);\n\tcolors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);\n\tcolors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);\n\tcolors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);\n\tcolors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);\n\tcolors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);\n\tcolors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);\n\tcolors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);\n\tcolors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);\n\tcolors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);\n\tcolors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);\n\tcolors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);\n\tcolors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);\n\tcolors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);\n\tcolors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);\n\tcolors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);\n\tcolors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);\n\tcolors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);\n\tcolors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);\n\tcolors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);\n\tcolors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);\n\tcolors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);\n\tcolors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];\n\tcolors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);\n\tcolors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);\n\tcolors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);\n\tcolors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);\n\tcolors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);\n\tcolors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f);\n\tcolors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f);   // Prefer using Alpha=1.0 here\n\tcolors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n\tcolors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);\n\tcolors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);\n\tcolors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);\n\tcolors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];\n\tcolors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);\n\tcolors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);\n\tcolors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImDrawList\n//-----------------------------------------------------------------------------\n\nImDrawListSharedData::ImDrawListSharedData()\n{\n\tmemset(this, 0, sizeof(*this));\n\tfor (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)\n\t{\n\t\tconst float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);\n\t\tArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));\n\t}\n\tArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);\n}\n\nvoid ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)\n{\n\tif (CircleSegmentMaxError == max_error)\n\t\treturn;\n\n\tIM_ASSERT(max_error > 0.0f);\n\tCircleSegmentMaxError = max_error;\n\tfor (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)\n\t{\n\t\tconst float radius = (float)i;\n\t\tCircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);\n\t}\n\tArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);\n}\n\n// Initialize before use in a new frame. We always have a command ready in the buffer.\nvoid ImDrawList::_ResetForNewFrame()\n{\n\t// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.\n\tIM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);\n\tIM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));\n\tIM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));\n\tif (_Splitter._Count > 1)\n\t\t_Splitter.Merge(this);\n\n\tCmdBuffer.resize(0);\n\tIdxBuffer.resize(0);\n\tVtxBuffer.resize(0);\n\tFlags = _Data->InitialFlags;\n\tmemset(&_CmdHeader, 0, sizeof(_CmdHeader));\n\t_VtxCurrentIdx = 0;\n\t_VtxWritePtr = NULL;\n\t_IdxWritePtr = NULL;\n\t_ClipRectStack.resize(0);\n\t_TextureIdStack.resize(0);\n\t_Path.resize(0);\n\t_Splitter.Clear();\n\tCmdBuffer.push_back(ImDrawCmd());\n\t_FringeScale = 1.0f;\n}\n\nvoid ImDrawList::_ClearFreeMemory()\n{\n\tCmdBuffer.clear();\n\tIdxBuffer.clear();\n\tVtxBuffer.clear();\n\tFlags = ImDrawListFlags_None;\n\t_VtxCurrentIdx = 0;\n\t_VtxWritePtr = NULL;\n\t_IdxWritePtr = NULL;\n\t_ClipRectStack.clear();\n\t_TextureIdStack.clear();\n\t_Path.clear();\n\t_Splitter.ClearFreeMemory();\n}\n\nImDrawList* ImDrawList::CloneOutput() const\n{\n\tImDrawList* dst = IM_NEW(ImDrawList(_Data));\n\tdst->CmdBuffer = CmdBuffer;\n\tdst->IdxBuffer = IdxBuffer;\n\tdst->VtxBuffer = VtxBuffer;\n\tdst->Flags = Flags;\n\treturn dst;\n}\n\nvoid ImDrawList::AddDrawCmd()\n{\n\tImDrawCmd draw_cmd;\n\tdraw_cmd.ClipRect = _CmdHeader.ClipRect;    // Same as calling ImDrawCmd_HeaderCopy()\n\tdraw_cmd.TextureId = _CmdHeader.TextureId;\n\tdraw_cmd.VtxOffset = _CmdHeader.VtxOffset;\n\tdraw_cmd.IdxOffset = IdxBuffer.Size;\n\n\tIM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);\n\tCmdBuffer.push_back(draw_cmd);\n}\n\n// Pop trailing draw command (used before merging or presenting to user)\n// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL\nvoid ImDrawList::_PopUnusedDrawCmd()\n{\n\twhile (CmdBuffer.Size > 0)\n\t{\n\t\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\t\tif (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)\n\t\t\treturn;// break;\n\t\tCmdBuffer.pop_back();\n\t}\n}\n\nvoid ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)\n{\n\tIM_ASSERT_PARANOID(CmdBuffer.Size > 0);\n\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tIM_ASSERT(curr_cmd->UserCallback == NULL);\n\tif (curr_cmd->ElemCount != 0)\n\t{\n\t\tAddDrawCmd();\n\t\tcurr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\t}\n\tcurr_cmd->UserCallback = callback;\n\tcurr_cmd->UserCallbackData = callback_data;\n\n\tAddDrawCmd(); // Force a new command after us (see comment below)\n}\n\n// Compare ClipRect, TextureId and VtxOffset with a single memcmp()\n#define ImDrawCmd_HeaderSize                            (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))\n#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS)       (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize))    // Compare ClipRect, TextureId, VtxOffset\n#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC)          (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize))    // Copy ClipRect, TextureId, VtxOffset\n#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1)  (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)\n\n// Try to merge two last draw commands\nvoid ImDrawList::_TryMergeDrawCmds()\n{\n\tIM_ASSERT_PARANOID(CmdBuffer.Size > 0);\n\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tImDrawCmd* prev_cmd = curr_cmd - 1;\n\tif (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)\n\t{\n\t\tprev_cmd->ElemCount += curr_cmd->ElemCount;\n\t\tCmdBuffer.pop_back();\n\t}\n}\n\n// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.\n// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.\nvoid ImDrawList::_OnChangedClipRect()\n{\n\t// If current command is used with different settings we need to add a new command\n\tIM_ASSERT_PARANOID(CmdBuffer.Size > 0);\n\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tif (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)\n\t{\n\t\tAddDrawCmd();\n\t\treturn;\n\t}\n\tIM_ASSERT(curr_cmd->UserCallback == NULL);\n\n\t// Try to merge with previous command if it matches, else use current command\n\tImDrawCmd* prev_cmd = curr_cmd - 1;\n\tif (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)\n\t{\n\t\tCmdBuffer.pop_back();\n\t\treturn;\n\t}\n\n\tcurr_cmd->ClipRect = _CmdHeader.ClipRect;\n}\n\nvoid ImDrawList::_OnChangedTextureID()\n{\n\t// If current command is used with different settings we need to add a new command\n\tIM_ASSERT_PARANOID(CmdBuffer.Size > 0);\n\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tif (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)\n\t{\n\t\tAddDrawCmd();\n\t\treturn;\n\t}\n\tIM_ASSERT(curr_cmd->UserCallback == NULL);\n\n\t// Try to merge with previous command if it matches, else use current command\n\tImDrawCmd* prev_cmd = curr_cmd - 1;\n\tif (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)\n\t{\n\t\tCmdBuffer.pop_back();\n\t\treturn;\n\t}\n\n\tcurr_cmd->TextureId = _CmdHeader.TextureId;\n}\n\nvoid ImDrawList::_OnChangedVtxOffset()\n{\n\t// We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.\n\t_VtxCurrentIdx = 0;\n\tIM_ASSERT_PARANOID(CmdBuffer.Size > 0);\n\tImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\t//IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349\n\tif (curr_cmd->ElemCount != 0)\n\t{\n\t\tAddDrawCmd();\n\t\treturn;\n\t}\n\tIM_ASSERT(curr_cmd->UserCallback == NULL);\n\tcurr_cmd->VtxOffset = _CmdHeader.VtxOffset;\n}\n\nint ImDrawList::_CalcCircleAutoSegmentCount(float radius) const\n{\n\t// Automatic segment count\n\tconst int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy\n\tif (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))\n\t\treturn _Data->CircleSegmentCounts[radius_idx]; // Use cached value\n\telse\n\t\treturn IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);\n}\n\n// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)\nvoid ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect)\n{\n\tImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);\n\tif (intersect_with_current_clip_rect)\n\t{\n\t\tImVec4 current = _CmdHeader.ClipRect;\n\t\tif (cr.x < current.x) cr.x = current.x;\n\t\tif (cr.y < current.y) cr.y = current.y;\n\t\tif (cr.z > current.z) cr.z = current.z;\n\t\tif (cr.w > current.w) cr.w = current.w;\n\t}\n\tcr.z = ImMax(cr.x, cr.z);\n\tcr.w = ImMax(cr.y, cr.w);\n\n\t_ClipRectStack.push_back(cr);\n\t_CmdHeader.ClipRect = cr;\n\t_OnChangedClipRect();\n}\n\nvoid ImDrawList::PushClipRectFullScreen()\n{\n\tPushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));\n}\n\nvoid ImDrawList::PopClipRect()\n{\n\t_ClipRectStack.pop_back();\n\t_CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];\n\t_OnChangedClipRect();\n}\n\nvoid ImDrawList::PushTextureID(ImTextureID texture_id)\n{\n\t_TextureIdStack.push_back(texture_id);\n\t_CmdHeader.TextureId = texture_id;\n\t_OnChangedTextureID();\n}\n\nvoid ImDrawList::PopTextureID()\n{\n\t_TextureIdStack.pop_back();\n\t_CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1];\n\t_OnChangedTextureID();\n}\n\n// Reserve space for a number of vertices and indices.\n// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or\n// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.\nvoid ImDrawList::PrimReserve(int idx_count, int vtx_count)\n{\n\t// Large mesh support (when enabled)\n\tIM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);\n\tif (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))\n\t{\n\t\t// FIXME: In theory we should be testing that vtx_count <64k here.\n\t\t// In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us\n\t\t// to not make that check until we rework the text functions to handle clipping and large horizontal lines better.\n\t\t_CmdHeader.VtxOffset = VtxBuffer.Size;\n\t\t_OnChangedVtxOffset();\n\t}\n\n\tImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tdraw_cmd->ElemCount += idx_count;\n\n\tint vtx_buffer_old_size = VtxBuffer.Size;\n\tVtxBuffer.resize(vtx_buffer_old_size + vtx_count);\n\t_VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;\n\n\tint idx_buffer_old_size = IdxBuffer.Size;\n\tIdxBuffer.resize(idx_buffer_old_size + idx_count);\n\t_IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;\n}\n\n// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve().\nvoid ImDrawList::PrimUnreserve(int idx_count, int vtx_count)\n{\n\tIM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);\n\n\tImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];\n\tdraw_cmd->ElemCount -= idx_count;\n\tVtxBuffer.shrink(VtxBuffer.Size - vtx_count);\n\tIdxBuffer.shrink(IdxBuffer.Size - idx_count);\n}\n\n// Fully unrolled with inline call to keep our debug builds decently fast.\nvoid ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)\n{\n\tImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);\n\tImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;\n\t_IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);\n\t_IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);\n\t_VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;\n\t_VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;\n\t_VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;\n\t_VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;\n\t_VtxWritePtr += 4;\n\t_VtxCurrentIdx += 4;\n\t_IdxWritePtr += 6;\n}\n\nvoid ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)\n{\n\tImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);\n\tImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;\n\t_IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);\n\t_IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);\n\t_VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;\n\t_VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;\n\t_VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;\n\t_VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;\n\t_VtxWritePtr += 4;\n\t_VtxCurrentIdx += 4;\n\t_IdxWritePtr += 6;\n}\n\nvoid ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)\n{\n\tImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;\n\t_IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);\n\t_IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);\n\t_VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;\n\t_VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;\n\t_VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;\n\t_VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;\n\t_VtxWritePtr += 4;\n\t_VtxCurrentIdx += 4;\n\t_IdxWritePtr += 6;\n}\n\n// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.\n// - Those macros expects l-values and need to be used as their own statement.\n// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers.\n#define IM_NORMALIZE2F_OVER_ZERO(VX,VY)     { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0\n#define IM_FIXNORMAL2F_MAX_INVLEN2          100.0f // 500.0f (see #4053, #3366)\n#define IM_FIXNORMAL2F(VX,VY)               { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0\n\n// TODO: Thickness anti-aliased lines cap are missing their AA fringe.\n// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.\nvoid ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)\n{\n\tif (points_count < 2 || (col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tconst bool closed = (flags & ImDrawFlags_Closed) != 0;\n\tconst ImVec2 opaque_uv = _Data->TexUvWhitePixel;\n\tconst int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw\n\tconst bool thick_line = (thickness > _FringeScale);\n\n\tif (Flags & ImDrawListFlags_AntiAliasedLines)\n\t{\n\t\t// Anti-aliased stroke\n\t\tconst float AA_SIZE = _FringeScale;\n\t\tconst ImU32 col_trans = col & ~IM_COL32_A_MASK;\n\n\t\t// Thicknesses <1.0 should behave like thickness 1.0\n\t\tthickness = ImMax(thickness, 1.0f);\n\t\tconst int integer_thickness = (int)thickness;\n\t\tconst float fractional_thickness = thickness - integer_thickness;\n\n\t\t// Do we want to draw this line using a texture?\n\t\t// - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.\n\t\t// - If AA_SIZE is not 1.0f we cannot use the texture path.\n\t\tconst bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f);\n\n\t\t// We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off\n\t\tIM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));\n\n\t\tconst int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);\n\t\tconst int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);\n\t\tPrimReserve(idx_count, vtx_count);\n\n\t\t// Temporary buffer\n\t\t// The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point\n\t\t_Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5));\n\t\tImVec2* temp_normals = _Data->TempBuffer.Data;\n\t\tImVec2* temp_points = temp_normals + points_count;\n\n\t\t// Calculate normals (tangents) for each line segment\n\t\tfor (int i1 = 0; i1 < count; i1++)\n\t\t{\n\t\t\tconst int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;\n\t\t\tfloat dx = points[i2].x - points[i1].x;\n\t\t\tfloat dy = points[i2].y - points[i1].y;\n\t\t\tIM_NORMALIZE2F_OVER_ZERO(dx, dy);\n\t\t\ttemp_normals[i1].x = dy;\n\t\t\ttemp_normals[i1].y = -dx;\n\t\t}\n\t\tif (!closed)\n\t\t\ttemp_normals[points_count - 1] = temp_normals[points_count - 2];\n\n\t\t// If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point\n\t\tif (use_texture || !thick_line)\n\t\t{\n\t\t\t// [PATH 1] Texture-based lines (thick or non-thick)\n\t\t\t// [PATH 2] Non texture-based lines (non-thick)\n\n\t\t\t// The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus \"one pixel\" for AA.\n\t\t\t// - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture\n\t\t\t//   (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.\n\t\t\t// - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to\n\t\t\t//   allow scaling geometry while preserving one-screen-pixel AA fringe).\n\t\t\tconst float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;\n\n\t\t\t// If line is not closed, the first and last points need to be generated differently as there are no normals to blend\n\t\t\tif (!closed)\n\t\t\t{\n\t\t\t\ttemp_points[0] = points[0] + temp_normals[0] * half_draw_size;\n\t\t\t\ttemp_points[1] = points[0] - temp_normals[0] * half_draw_size;\n\t\t\t\ttemp_points[(points_count - 1) * 2 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * half_draw_size;\n\t\t\t\ttemp_points[(points_count - 1) * 2 + 1] = points[points_count - 1] - temp_normals[points_count - 1] * half_draw_size;\n\t\t\t}\n\n\t\t\t// Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges\n\t\t\t// This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)\n\t\t\t// FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.\n\t\t\tunsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment\n\t\t\tfor (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment\n\t\t\t{\n\t\t\t\tconst int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment\n\t\t\t\tconst unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment\n\n\t\t\t\t// Average normals\n\t\t\t\tfloat dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;\n\t\t\t\tfloat dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;\n\t\t\t\tIM_FIXNORMAL2F(dm_x, dm_y);\n\t\t\t\tdm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area\n\t\t\t\tdm_y *= half_draw_size;\n\n\t\t\t\t// Add temporary vertexes for the outer edges\n\t\t\t\tImVec2* out_vtx = &temp_points[i2 * 2];\n\t\t\t\tout_vtx[0].x = points[i2].x + dm_x;\n\t\t\t\tout_vtx[0].y = points[i2].y + dm_y;\n\t\t\t\tout_vtx[1].x = points[i2].x - dm_x;\n\t\t\t\tout_vtx[1].y = points[i2].y - dm_y;\n\n\t\t\t\tif (use_texture)\n\t\t\t\t{\n\t\t\t\t\t// Add indices for two triangles\n\t\t\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri\n\t\t\t\t\t_IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri\n\t\t\t\t\t_IdxWritePtr += 6;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Add indexes for four triangles\n\t\t\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1\n\t\t\t\t\t_IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2\n\t\t\t\t\t_IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1\n\t\t\t\t\t_IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2\n\t\t\t\t\t_IdxWritePtr += 12;\n\t\t\t\t}\n\n\t\t\t\tidx1 = idx2;\n\t\t\t}\n\n\t\t\t// Add vertexes for each point on the line\n\t\t\tif (use_texture)\n\t\t\t{\n\t\t\t\t// If we're using textures we only need to emit the left/right edge vertices\n\t\t\t\tImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];\n\t\t\t\t/*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false!\n\t\t\t\t{\n\t\t\t\t\tconst ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];\n\t\t\t\t\ttex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp()\n\t\t\t\t\ttex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;\n\t\t\t\t\ttex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;\n\t\t\t\t\ttex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;\n\t\t\t\t}*/\n\t\t\t\tImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);\n\t\t\t\tImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);\n\t\t\t\tfor (int i = 0; i < points_count; i++)\n\t\t\t\t{\n\t\t\t\t\t_VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge\n\t\t\t\t\t_VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge\n\t\t\t\t\t_VtxWritePtr += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If we're not using a texture, we need the center vertex as well\n\t\t\t\tfor (int i = 0; i < points_count; i++)\n\t\t\t\t{\n\t\t\t\t\t_VtxWritePtr[0].pos = points[i];              _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;       // Center of line\n\t\t\t\t\t_VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge\n\t\t\t\t\t_VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge\n\t\t\t\t\t_VtxWritePtr += 3;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point\n\t\t\tconst float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;\n\n\t\t\t// If line is not closed, the first and last points need to be generated differently as there are no normals to blend\n\t\t\tif (!closed)\n\t\t\t{\n\t\t\t\tconst int points_last = points_count - 1;\n\t\t\t\ttemp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);\n\t\t\t\ttemp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);\n\t\t\t\ttemp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);\n\t\t\t\ttemp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);\n\t\t\t\ttemp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE);\n\t\t\t\ttemp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);\n\t\t\t\ttemp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);\n\t\t\t\ttemp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE);\n\t\t\t}\n\n\t\t\t// Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges\n\t\t\t// This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)\n\t\t\t// FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.\n\t\t\tunsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment\n\t\t\tfor (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment\n\t\t\t{\n\t\t\t\tconst int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment\n\t\t\t\tconst unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment\n\n\t\t\t\t// Average normals\n\t\t\t\tfloat dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;\n\t\t\t\tfloat dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;\n\t\t\t\tIM_FIXNORMAL2F(dm_x, dm_y);\n\t\t\t\tfloat dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);\n\t\t\t\tfloat dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);\n\t\t\t\tfloat dm_in_x = dm_x * half_inner_thickness;\n\t\t\t\tfloat dm_in_y = dm_y * half_inner_thickness;\n\n\t\t\t\t// Add temporary vertices\n\t\t\t\tImVec2* out_vtx = &temp_points[i2 * 4];\n\t\t\t\tout_vtx[0].x = points[i2].x + dm_out_x;\n\t\t\t\tout_vtx[0].y = points[i2].y + dm_out_y;\n\t\t\t\tout_vtx[1].x = points[i2].x + dm_in_x;\n\t\t\t\tout_vtx[1].y = points[i2].y + dm_in_y;\n\t\t\t\tout_vtx[2].x = points[i2].x - dm_in_x;\n\t\t\t\tout_vtx[2].y = points[i2].y - dm_in_y;\n\t\t\t\tout_vtx[3].x = points[i2].x - dm_out_x;\n\t\t\t\tout_vtx[3].y = points[i2].y - dm_out_y;\n\n\t\t\t\t// Add indexes\n\t\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);\n\t\t\t\t_IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1);\n\t\t\t\t_IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);\n\t\t\t\t_IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);\n\t\t\t\t_IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);\n\t\t\t\t_IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);\n\t\t\t\t_IdxWritePtr += 18;\n\n\t\t\t\tidx1 = idx2;\n\t\t\t}\n\n\t\t\t// Add vertices\n\t\t\tfor (int i = 0; i < points_count; i++)\n\t\t\t{\n\t\t\t\t_VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans;\n\t\t\t\t_VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;\n\t\t\t\t_VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;\n\t\t\t\t_VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans;\n\t\t\t\t_VtxWritePtr += 4;\n\t\t\t}\n\t\t}\n\t\t_VtxCurrentIdx += (ImDrawIdx)vtx_count;\n\t}\n\telse\n\t{\n\t\t// [PATH 4] Non texture-based, Non anti-aliased lines\n\t\tconst int idx_count = count * 6;\n\t\tconst int vtx_count = count * 4;    // FIXME-OPT: Not sharing edges\n\t\tPrimReserve(idx_count, vtx_count);\n\n\t\tfor (int i1 = 0; i1 < count; i1++)\n\t\t{\n\t\t\tconst int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;\n\t\t\tconst ImVec2& p1 = points[i1];\n\t\t\tconst ImVec2& p2 = points[i2];\n\n\t\t\tfloat dx = p2.x - p1.x;\n\t\t\tfloat dy = p2.y - p1.y;\n\t\t\tIM_NORMALIZE2F_OVER_ZERO(dx, dy);\n\t\t\tdx *= (thickness * 0.5f);\n\t\t\tdy *= (thickness * 0.5f);\n\n\t\t\t_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;\n\t\t\t_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;\n\t\t\t_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;\n\t\t\t_VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col;\n\t\t\t_VtxWritePtr += 4;\n\n\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);\n\t\t\t_IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);\n\t\t\t_IdxWritePtr += 6;\n\t\t\t_VtxCurrentIdx += 4;\n\t\t}\n\t}\n}\n\n// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.\n// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have \"inward\" anti-aliasing.\nvoid ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)\n{\n\tif (points_count < 3 || (col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tconst ImVec2 uv = _Data->TexUvWhitePixel;\n\n\tif (Flags & ImDrawListFlags_AntiAliasedFill)\n\t{\n\t\t// Anti-aliased Fill\n\t\tconst float AA_SIZE = _FringeScale;\n\t\tconst ImU32 col_trans = col & ~IM_COL32_A_MASK;\n\t\tconst int idx_count = (points_count - 2) * 3 + points_count * 6;\n\t\tconst int vtx_count = (points_count * 2);\n\t\tPrimReserve(idx_count, vtx_count);\n\n\t\t// Add indexes for fill\n\t\tunsigned int vtx_inner_idx = _VtxCurrentIdx;\n\t\tunsigned int vtx_outer_idx = _VtxCurrentIdx + 1;\n\t\tfor (int i = 2; i < points_count; i++)\n\t\t{\n\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));\n\t\t\t_IdxWritePtr += 3;\n\t\t}\n\n\t\t// Compute normals\n\t\t_Data->TempBuffer.reserve_discard(points_count);\n\t\tImVec2* temp_normals = _Data->TempBuffer.Data;\n\t\tfor (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)\n\t\t{\n\t\t\tconst ImVec2& p0 = points[i0];\n\t\t\tconst ImVec2& p1 = points[i1];\n\t\t\tfloat dx = p1.x - p0.x;\n\t\t\tfloat dy = p1.y - p0.y;\n\t\t\tIM_NORMALIZE2F_OVER_ZERO(dx, dy);\n\t\t\ttemp_normals[i0].x = dy;\n\t\t\ttemp_normals[i0].y = -dx;\n\t\t}\n\n\t\tfor (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)\n\t\t{\n\t\t\t// Average normals\n\t\t\tconst ImVec2& n0 = temp_normals[i0];\n\t\t\tconst ImVec2& n1 = temp_normals[i1];\n\t\t\tfloat dm_x = (n0.x + n1.x) * 0.5f;\n\t\t\tfloat dm_y = (n0.y + n1.y) * 0.5f;\n\t\t\tIM_FIXNORMAL2F(dm_x, dm_y);\n\t\t\tdm_x *= AA_SIZE * 0.5f;\n\t\t\tdm_y *= AA_SIZE * 0.5f;\n\n\t\t\t// Add vertices\n\t\t\t_VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;        // Inner\n\t\t\t_VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;  // Outer\n\t\t\t_VtxWritePtr += 2;\n\n\t\t\t// Add indexes for fringes\n\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));\n\t\t\t_IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));\n\t\t\t_IdxWritePtr += 6;\n\t\t}\n\t\t_VtxCurrentIdx += (ImDrawIdx)vtx_count;\n\t}\n\telse\n\t{\n\t\t// Non Anti-aliased Fill\n\t\tconst int idx_count = (points_count - 2) * 3;\n\t\tconst int vtx_count = points_count;\n\t\tPrimReserve(idx_count, vtx_count);\n\t\tfor (int i = 0; i < vtx_count; i++)\n\t\t{\n\t\t\t_VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;\n\t\t\t_VtxWritePtr++;\n\t\t}\n\t\tfor (int i = 2; i < points_count; i++)\n\t\t{\n\t\t\t_IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);\n\t\t\t_IdxWritePtr += 3;\n\t\t}\n\t\t_VtxCurrentIdx += (ImDrawIdx)vtx_count;\n\t}\n}\n\nvoid ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)\n{\n\tif (radius < 0.5f)\n\t{\n\t\t_Path.push_back(center);\n\t\treturn;\n\t}\n\n\t// Calculate arc auto segment step size\n\tif (a_step <= 0)\n\t\ta_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius);\n\n\t// Make sure we never do steps larger than one quarter of the circle\n\ta_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);\n\n\tconst int sample_range = ImAbs(a_max_sample - a_min_sample);\n\tconst int a_next_step = a_step;\n\n\tint samples = sample_range + 1;\n\tbool extra_max_sample = false;\n\tif (a_step > 1)\n\t{\n\t\tsamples = sample_range / a_step + 1;\n\t\tconst int overstep = sample_range % a_step;\n\n\t\tif (overstep > 0)\n\t\t{\n\t\t\textra_max_sample = true;\n\t\t\tsamples++;\n\n\t\t\t// When we have overstep to avoid awkwardly looking one long line and one tiny one at the end,\n\t\t\t// distribute first step range evenly between them by reducing first step size.\n\t\t\tif (sample_range > 0)\n\t\t\t\ta_step -= (a_step - overstep) / 2;\n\t\t}\n\t}\n\n\t_Path.resize(_Path.Size + samples);\n\tImVec2* out_ptr = _Path.Data + (_Path.Size - samples);\n\n\tint sample_index = a_min_sample;\n\tif (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)\n\t{\n\t\tsample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\t\tif (sample_index < 0)\n\t\t\tsample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\t}\n\n\tif (a_max_sample >= a_min_sample)\n\t{\n\t\tfor (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)\n\t\t{\n\t\t\t// a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more\n\t\t\tif (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)\n\t\t\t\tsample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\n\t\t\tconst ImVec2 s = _Data->ArcFastVtx[sample_index];\n\t\t\tout_ptr->x = center.x + s.x * radius;\n\t\t\tout_ptr->y = center.y + s.y * radius;\n\t\t\tout_ptr++;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step)\n\t\t{\n\t\t\t// a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more\n\t\t\tif (sample_index < 0)\n\t\t\t\tsample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\n\t\t\tconst ImVec2 s = _Data->ArcFastVtx[sample_index];\n\t\t\tout_ptr->x = center.x + s.x * radius;\n\t\t\tout_ptr->y = center.y + s.y * radius;\n\t\t\tout_ptr++;\n\t\t}\n\t}\n\n\tif (extra_max_sample)\n\t{\n\t\tint normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\t\tif (normalized_max_sample < 0)\n\t\t\tnormalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\n\t\tconst ImVec2 s = _Data->ArcFastVtx[normalized_max_sample];\n\t\tout_ptr->x = center.x + s.x * radius;\n\t\tout_ptr->y = center.y + s.y * radius;\n\t\tout_ptr++;\n\t}\n\n\tIM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr);\n}\n\nvoid ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)\n{\n\tif (radius < 0.5f)\n\t{\n\t\t_Path.push_back(center);\n\t\treturn;\n\t}\n\n\t// Note that we are adding a point at both a_min and a_max.\n\t// If you are trying to draw a full closed circle you don't want the overlapping points!\n\t_Path.reserve(_Path.Size + (num_segments + 1));\n\tfor (int i = 0; i <= num_segments; i++)\n\t{\n\t\tconst float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);\n\t\t_Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));\n\t}\n}\n\n// 0: East, 3: South, 6: West, 9: North, 12: East\nvoid ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)\n{\n\tif (radius < 0.5f)\n\t{\n\t\t_Path.push_back(center);\n\t\treturn;\n\t}\n\t_PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0);\n}\n\nvoid ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)\n{\n\tif (radius < 0.5f)\n\t{\n\t\t_Path.push_back(center);\n\t\treturn;\n\t}\n\n\tif (num_segments > 0)\n\t{\n\t\t_PathArcToN(center, radius, a_min, a_max, num_segments);\n\t\treturn;\n\t}\n\n\t// Automatic segment count\n\tif (radius <= _Data->ArcFastRadiusCutoff)\n\t{\n\t\tconst bool a_is_reverse = a_max < a_min;\n\n\t\t// We are going to use precomputed values for mid samples.\n\t\t// Determine first and last sample in lookup table that belong to the arc.\n\t\tconst float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);\n\t\tconst float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);\n\n\t\tconst int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f);\n\t\tconst int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f);\n\t\tconst int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);\n\n\t\tconst float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\t\tconst float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;\n\t\tconst bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f;\n\t\tconst bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f;\n\n\t\t_Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));\n\t\tif (a_emit_start)\n\t\t\t_Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));\n\t\tif (a_mid_samples > 0)\n\t\t\t_PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);\n\t\tif (a_emit_end)\n\t\t\t_Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));\n\t}\n\telse\n\t{\n\t\tconst float arc_length = ImAbs(a_max - a_min);\n\t\tconst int circle_segment_count = _CalcCircleAutoSegmentCount(radius);\n\t\tconst int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));\n\t\t_PathArcToN(center, radius, a_min, a_max, arc_segment_count);\n\t}\n}\n\nImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)\n{\n\tfloat u = 1.0f - t;\n\tfloat w1 = u * u * u;\n\tfloat w2 = 3 * u * u * t;\n\tfloat w3 = 3 * u * t * t;\n\tfloat w4 = t * t * t;\n\treturn ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y);\n}\n\nImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)\n{\n\tfloat u = 1.0f - t;\n\tfloat w1 = u * u;\n\tfloat w2 = 2 * u * t;\n\tfloat w3 = t * t;\n\treturn ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y);\n}\n\n// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp\nstatic void PathBezierCubicCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)\n{\n\tfloat dx = x4 - x1;\n\tfloat dy = y4 - y1;\n\tfloat d2 = (x2 - x4) * dy - (y2 - y4) * dx;\n\tfloat d3 = (x3 - x4) * dy - (y3 - y4) * dx;\n\td2 = (d2 >= 0) ? d2 : -d2;\n\td3 = (d3 >= 0) ? d3 : -d3;\n\tif ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))\n\t{\n\t\tpath->push_back(ImVec2(x4, y4));\n\t}\n\telse if (level < 10)\n\t{\n\t\tfloat x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;\n\t\tfloat x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;\n\t\tfloat x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;\n\t\tfloat x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;\n\t\tfloat x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;\n\t\tfloat x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;\n\t\tPathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);\n\t\tPathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);\n\t}\n}\n\nstatic void PathBezierQuadraticCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level)\n{\n\tfloat dx = x3 - x1, dy = y3 - y1;\n\tfloat det = (x2 - x3) * dy - (y2 - y3) * dx;\n\tif (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))\n\t{\n\t\tpath->push_back(ImVec2(x3, y3));\n\t}\n\telse if (level < 10)\n\t{\n\t\tfloat x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;\n\t\tfloat x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;\n\t\tfloat x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;\n\t\tPathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);\n\t\tPathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);\n\t}\n}\n\nvoid ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)\n{\n\tImVec2 p1 = _Path.back();\n\tif (num_segments == 0)\n\t{\n\t\tIM_ASSERT(_Data->CurveTessellationTol > 0.0f);\n\t\tPathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated\n\t}\n\telse\n\t{\n\t\tfloat t_step = 1.0f / (float)num_segments;\n\t\tfor (int i_step = 1; i_step <= num_segments; i_step++)\n\t\t\t_Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));\n\t}\n}\n\nvoid ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)\n{\n\tImVec2 p1 = _Path.back();\n\tif (num_segments == 0)\n\t{\n\t\tIM_ASSERT(_Data->CurveTessellationTol > 0.0f);\n\t\tPathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated\n\t}\n\telse\n\t{\n\t\tfloat t_step = 1.0f / (float)num_segments;\n\t\tfor (int i_step = 1; i_step <= num_segments; i_step++)\n\t\t\t_Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));\n\t}\n}\n\nIM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));\nstatic inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)\n{\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\t// Obsoleted in 1.82 (from February 2021)\n\t// Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)\n\t//   ~0   --> ImDrawFlags_RoundCornersAll or 0\n\tif (flags == ~0)\n\t\treturn ImDrawFlags_RoundCornersAll;\n\n\t// Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations)\n\t//   0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!)\n\t//   0x02 --> ImDrawFlags_RoundCornersTopRight\n\t//   0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight\n\t//   0x04 --> ImDrawFlags_RoundCornersBotLeft\n\t//   0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft\n\t//   ...\n\t//   0x0F --> ImDrawFlags_RoundCornersAll or 0\n\t// (See all values in ImDrawCornerFlags_)\n\tif (flags >= 0x01 && flags <= 0x0F)\n\t\treturn (flags << 4);\n\n\t// We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'\n#endif\n\n\t// If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.\n\t// Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc...\n\tIM_ASSERT((flags & 0x0F) == 0 && \"Misuse of legacy hardcoded ImDrawCornerFlags values!\");\n\n\tif ((flags & ImDrawFlags_RoundCornersMask_) == 0)\n\t\tflags |= ImDrawFlags_RoundCornersAll;\n\n\treturn flags;\n}\n\nvoid ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)\n{\n\tif (rounding >= 0.5f)\n\t{\n\t\tflags = FixRectCornerFlags(flags);\n\t\trounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);\n\t\trounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);\n\t}\n\tif (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)\n\t{\n\t\tPathLineTo(a);\n\t\tPathLineTo(ImVec2(b.x, a.y));\n\t\tPathLineTo(b);\n\t\tPathLineTo(ImVec2(a.x, b.y));\n\t}\n\telse\n\t{\n\t\tconst float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f;\n\t\tconst float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f;\n\t\tconst float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f;\n\t\tconst float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f;\n\t\tPathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);\n\t\tPathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);\n\t\tPathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);\n\t\tPathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);\n\t}\n}\n\nvoid ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\tPathLineTo(p1 + ImVec2(0.5f, 0.5f));\n\tPathLineTo(p2 + ImVec2(0.5f, 0.5f));\n\tPathStroke(col, 0, thickness);\n}\n\n// p_min = upper-left, p_max = lower-right\n// Note we don't render 1 pixels sized rectangles properly.\nvoid ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\tif (Flags & ImDrawListFlags_AntiAliasedLines)\n\t\tPathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);\n\telse\n\t\tPathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes.\n\tPathStroke(col, ImDrawFlags_Closed, thickness);\n}\n\nvoid ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\tif (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)\n\t{\n\t\tPrimReserve(6, 4);\n\t\tPrimRect(p_min, p_max, col);\n\t}\n\telse\n\t{\n\t\tPathRect(p_min, p_max, rounding, flags);\n\t\tPathFillConvex(col);\n\t}\n}\n\n// p_min = upper-left, p_max = lower-right\nvoid ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)\n{\n\tif (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tconst ImVec2 uv = _Data->TexUvWhitePixel;\n\tPrimReserve(6, 4);\n\tPrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));\n\tPrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));\n\tPrimWriteVtx(p_min, uv, col_upr_left);\n\tPrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);\n\tPrimWriteVtx(p_max, uv, col_bot_right);\n\tPrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);\n}\n\nvoid ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathLineTo(p2);\n\tPathLineTo(p3);\n\tPathLineTo(p4);\n\tPathStroke(col, ImDrawFlags_Closed, thickness);\n}\n\nvoid ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathLineTo(p2);\n\tPathLineTo(p3);\n\tPathLineTo(p4);\n\tPathFillConvex(col);\n}\n\nvoid ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathLineTo(p2);\n\tPathLineTo(p3);\n\tPathStroke(col, ImDrawFlags_Closed, thickness);\n}\n\nvoid ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathLineTo(p2);\n\tPathLineTo(p3);\n\tPathFillConvex(col);\n}\n\nvoid ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)\n\t\treturn;\n\n\tif (num_segments <= 0)\n\t{\n\t\t// Use arc with automatic segment count\n\t\t_PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);\n\t\t_Path.Size--;\n\t}\n\telse\n\t{\n\t\t// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)\n\t\tnum_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);\n\n\t\t// Because we are filling a closed shape we remove 1 from the count of segments/points\n\t\tconst float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;\n\t\tPathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);\n\t}\n\n\tPathStroke(col, ImDrawFlags_Closed, thickness);\n}\n\nvoid ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)\n{\n\tif ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)\n\t\treturn;\n\n\tif (num_segments <= 0)\n\t{\n\t\t// Use arc with automatic segment count\n\t\t_PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);\n\t\t_Path.Size--;\n\t}\n\telse\n\t{\n\t\t// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)\n\t\tnum_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);\n\n\t\t// Because we are filling a closed shape we remove 1 from the count of segments/points\n\t\tconst float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;\n\t\tPathArcTo(center, radius, 0.0f, a_max, num_segments - 1);\n\t}\n\n\tPathFillConvex(col);\n}\n\n// Guaranteed to honor 'num_segments'\nvoid ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)\n{\n\tif ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)\n\t\treturn;\n\n\t// Because we are filling a closed shape we remove 1 from the count of segments/points\n\tconst float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;\n\tPathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);\n\tPathStroke(col, ImDrawFlags_Closed, thickness);\n}\n\n// Guaranteed to honor 'num_segments'\nvoid ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)\n{\n\tif ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)\n\t\treturn;\n\n\t// Because we are filling a closed shape we remove 1 from the count of segments/points\n\tconst float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;\n\tPathArcTo(center, radius, 0.0f, a_max, num_segments - 1);\n\tPathFillConvex(col);\n}\n\n// Cubic Bezier takes 4 controls points\nvoid ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathBezierCubicCurveTo(p2, p3, p4, num_segments);\n\tPathStroke(col, 0, thickness);\n}\n\n// Quadratic Bezier takes 3 controls points\nvoid ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tPathLineTo(p1);\n\tPathBezierQuadraticCurveTo(p2, p3, num_segments);\n\tPathStroke(col, 0, thickness);\n}\n\nvoid ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tif (text_end == NULL)\n\t\ttext_end = text_begin + strlen(text_begin);\n\tif (text_begin == text_end)\n\t\treturn;\n\n\t// Pull default font/size from the shared ImDrawListSharedData instance\n\tif (font == NULL)\n\t\tfont = _Data->Font;\n\tif (font_size == 0.0f)\n\t\tfont_size = _Data->FontSize;\n\n\tIM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId);  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.\n\n\tImVec4 clip_rect = _CmdHeader.ClipRect;\n\tif (cpu_fine_clip_rect)\n\t{\n\t\tclip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);\n\t\tclip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);\n\t\tclip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);\n\t\tclip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);\n\t}\n\tfont->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);\n}\n\nvoid ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)\n{\n\tAddText(NULL, 0.0f, pos, col, text_begin, text_end);\n}\n\nvoid ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tconst bool push_texture_id = user_texture_id != _CmdHeader.TextureId;\n\tif (push_texture_id)\n\t\tPushTextureID(user_texture_id);\n\n\tPrimReserve(6, 4);\n\tPrimRectUV(p_min, p_max, uv_min, uv_max, col);\n\n\tif (push_texture_id)\n\t\tPopTextureID();\n}\n\nvoid ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tconst bool push_texture_id = user_texture_id != _CmdHeader.TextureId;\n\tif (push_texture_id)\n\t\tPushTextureID(user_texture_id);\n\n\tPrimReserve(6, 4);\n\tPrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);\n\n\tif (push_texture_id)\n\t\tPopTextureID();\n}\n\nvoid ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags)\n{\n\tif ((col & IM_COL32_A_MASK) == 0)\n\t\treturn;\n\n\tflags = FixRectCornerFlags(flags);\n\tif (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)\n\t{\n\t\tAddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);\n\t\treturn;\n\t}\n\n\tconst bool push_texture_id = user_texture_id != _CmdHeader.TextureId;\n\tif (push_texture_id)\n\t\tPushTextureID(user_texture_id);\n\n\tint vert_start_idx = VtxBuffer.Size;\n\tPathRect(p_min, p_max, rounding, flags);\n\tPathFillConvex(col);\n\tint vert_end_idx = VtxBuffer.Size;\n\tImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);\n\n\tif (push_texture_id)\n\t\tPopTextureID();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImDrawListSplitter\n//-----------------------------------------------------------------------------\n// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..\n//-----------------------------------------------------------------------------\n\nvoid ImDrawListSplitter::ClearFreeMemory()\n{\n\tfor (int i = 0; i < _Channels.Size; i++)\n\t{\n\t\tif (i == _Current)\n\t\t\tmemset(&_Channels[i], 0, sizeof(_Channels[i]));  // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again\n\t\t_Channels[i]._CmdBuffer.clear();\n\t\t_Channels[i]._IdxBuffer.clear();\n\t}\n\t_Current = 0;\n\t_Count = 1;\n\t_Channels.clear();\n}\n\nvoid ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)\n{\n\tIM_UNUSED(draw_list);\n\tIM_ASSERT(_Current == 0 && _Count <= 1 && \"Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.\");\n\tint old_channels_count = _Channels.Size;\n\tif (old_channels_count < channels_count)\n\t{\n\t\t_Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable\n\t\t_Channels.resize(channels_count);\n\t}\n\t_Count = channels_count;\n\n\t// Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer\n\t// The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.\n\t// When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer\n\tmemset(&_Channels[0], 0, sizeof(ImDrawChannel));\n\tfor (int i = 1; i < channels_count; i++)\n\t{\n\t\tif (i >= old_channels_count)\n\t\t{\n\t\t\tIM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_Channels[i]._CmdBuffer.resize(0);\n\t\t\t_Channels[i]._IdxBuffer.resize(0);\n\t\t}\n\t}\n}\n\nvoid ImDrawListSplitter::Merge(ImDrawList* draw_list)\n{\n\t// Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.\n\tif (_Count <= 1)\n\t\treturn;\n\n\tSetCurrentChannel(draw_list, 0);\n\tdraw_list->_PopUnusedDrawCmd();\n\n\t// Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.\n\tint new_cmd_buffer_count = 0;\n\tint new_idx_buffer_count = 0;\n\tImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;\n\tint idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;\n\tfor (int i = 1; i < _Count; i++)\n\t{\n\t\tImDrawChannel& ch = _Channels[i];\n\t\tif (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()\n\t\t\tch._CmdBuffer.pop_back();\n\n\t\tif (ch._CmdBuffer.Size > 0 && last_cmd != NULL)\n\t\t{\n\t\t\t// Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.\n\t\t\t// Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter.\n\t\t\tImDrawCmd* next_cmd = &ch._CmdBuffer[0];\n\t\t\tif (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)\n\t\t\t{\n\t\t\t\t// Merge previous channel last draw command with current channel first draw command if matching.\n\t\t\t\tlast_cmd->ElemCount += next_cmd->ElemCount;\n\t\t\t\tidx_offset += next_cmd->ElemCount;\n\t\t\t\tch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.\n\t\t\t}\n\t\t}\n\t\tif (ch._CmdBuffer.Size > 0)\n\t\t\tlast_cmd = &ch._CmdBuffer.back();\n\t\tnew_cmd_buffer_count += ch._CmdBuffer.Size;\n\t\tnew_idx_buffer_count += ch._IdxBuffer.Size;\n\t\tfor (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)\n\t\t{\n\t\t\tch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;\n\t\t\tidx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;\n\t\t}\n\t}\n\tdraw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);\n\tdraw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);\n\n\t// Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)\n\tImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;\n\tImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;\n\tfor (int i = 1; i < _Count; i++)\n\t{\n\t\tImDrawChannel& ch = _Channels[i];\n\t\tif (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }\n\t\tif (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }\n\t}\n\tdraw_list->_IdxWritePtr = idx_write;\n\n\t// Ensure there's always a non-callback draw command trailing the command-buffer\n\tif (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)\n\t\tdraw_list->AddDrawCmd();\n\n\t// If current command is used with different settings we need to add a new command\n\tImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];\n\tif (curr_cmd->ElemCount == 0)\n\t\tImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset\n\telse if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)\n\t\tdraw_list->AddDrawCmd();\n\n\t_Count = 1;\n}\n\nvoid ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)\n{\n\tIM_ASSERT(idx >= 0 && idx < _Count);\n\tif (_Current == idx)\n\t\treturn;\n\n\t// Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()\n\tmemcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));\n\tmemcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));\n\t_Current = idx;\n\tmemcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));\n\tmemcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));\n\tdraw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;\n\n\t// If current command is used with different settings we need to add a new command\n\tImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];\n\tif (curr_cmd == NULL)\n\t\tdraw_list->AddDrawCmd();\n\telse if (curr_cmd->ElemCount == 0)\n\t\tImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset\n\telse if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)\n\t\tdraw_list->AddDrawCmd();\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImDrawData\n//-----------------------------------------------------------------------------\n\nvoid ImDrawData::Clear()\n{\n\tValid = false;\n\tCmdListsCount = TotalIdxCount = TotalVtxCount = 0;\n\tCmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them.\n\tDisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f);\n\tOwnerViewport = NULL;\n}\n\n// Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list\n// as long at it is expected that the result will be later merged into draw_data->CmdLists[].\nvoid ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)\n{\n\tif (draw_list->CmdBuffer.Size == 0)\n\t\treturn;\n\tif (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)\n\t\treturn;\n\n\t// Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.\n\t// May trigger for you if you are using PrimXXX functions incorrectly.\n\tIM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);\n\tIM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);\n\tif (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))\n\t\tIM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);\n\n\t// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)\n\t// If this assert triggers because you are drawing lots of stuff manually:\n\t// - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.\n\t//   Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.\n\t// - If you want large meshes with more than 64K vertices, you can either:\n\t//   (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.\n\t//       Most example backends already support this from 1.71. Pre-1.71 backends won't.\n\t//       Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.\n\t//   (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.\n\t//       Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:\n\t//         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);\n\t//       Your own engine or render API may use different parameters or function calls to specify index sizes.\n\t//       2 and 4 bytes indices are generally supported by most graphics API.\n\t// - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching\n\t//   the 64K limit to split your draw commands in multiple draw lists.\n\tif (sizeof(ImDrawIdx) == 2)\n\t\tIM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && \"Too many vertices in ImDrawList using 16-bit indices. Read comment above\");\n\n\t// Add to output list + records state in ImDrawData\n\tout_list->push_back(draw_list);\n\tdraw_data->CmdListsCount++;\n\tdraw_data->TotalVtxCount += draw_list->VtxBuffer.Size;\n\tdraw_data->TotalIdxCount += draw_list->IdxBuffer.Size;\n}\n\nvoid ImDrawData::AddDrawList(ImDrawList* draw_list)\n{\n\tIM_ASSERT(CmdLists.Size == CmdListsCount);\n\tdraw_list->_PopUnusedDrawCmd();\n\tImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list);\n}\n\n// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!\nvoid ImDrawData::DeIndexAllBuffers()\n{\n\tImVector<ImDrawVert> new_vtx_buffer;\n\tTotalVtxCount = TotalIdxCount = 0;\n\tfor (int i = 0; i < CmdListsCount; i++)\n\t{\n\t\tImDrawList* cmd_list = CmdLists[i];\n\t\tif (cmd_list->IdxBuffer.empty())\n\t\t\tcontinue;\n\t\tnew_vtx_buffer.resize(cmd_list->IdxBuffer.Size);\n\t\tfor (int j = 0; j < cmd_list->IdxBuffer.Size; j++)\n\t\t\tnew_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];\n\t\tcmd_list->VtxBuffer.swap(new_vtx_buffer);\n\t\tcmd_list->IdxBuffer.resize(0);\n\t\tTotalVtxCount += cmd_list->VtxBuffer.Size;\n\t}\n}\n\n// Helper to scale the ClipRect field of each ImDrawCmd.\n// Use if your final output buffer is at a different scale than draw_data->DisplaySize,\n// or if there is a difference between your window resolution and framebuffer resolution.\nvoid ImDrawData::ScaleClipRects(const ImVec2& fb_scale)\n{\n\tfor (ImDrawList* draw_list : CmdLists)\n\t\tfor (ImDrawCmd& cmd : draw_list->CmdBuffer)\n\t\t\tcmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, cmd.ClipRect.w * fb_scale.y);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] Helpers ShadeVertsXXX functions\n//-----------------------------------------------------------------------------\n\n// Generic linear color gradient, write to RGB fields, leave A untouched.\nvoid ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)\n{\n\tImVec2 gradient_extent = gradient_p1 - gradient_p0;\n\tfloat gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);\n\tImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;\n\tImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;\n\tconst int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;\n\tconst int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;\n\tconst int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;\n\tconst int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;\n\tconst int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;\n\tconst int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;\n\tfor (ImDrawVert* vert = vert_start; vert < vert_end; vert++)\n\t{\n\t\tfloat d = ImDot(vert->pos - gradient_p0, gradient_extent);\n\t\tfloat t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);\n\t\tint r = (int)(col0_r + col_delta_r * t);\n\t\tint g = (int)(col0_g + col_delta_g * t);\n\t\tint b = (int)(col0_b + col_delta_b * t);\n\t\tvert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);\n\t}\n}\n\n// Distribute UV over (a, b) rectangle\nvoid ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp)\n{\n\tconst ImVec2 size = b - a;\n\tconst ImVec2 uv_size = uv_b - uv_a;\n\tconst ImVec2 scale = ImVec2(\n\t\tsize.x != 0.0f ? (uv_size.x / size.x) : 0.0f,\n\t\tsize.y != 0.0f ? (uv_size.y / size.y) : 0.0f);\n\n\tImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;\n\tImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;\n\tif (clamp)\n\t{\n\t\tconst ImVec2 min = ImMin(uv_a, uv_b);\n\t\tconst ImVec2 max = ImMax(uv_a, uv_b);\n\t\tfor (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)\n\t\t\tvertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);\n\t}\n\telse\n\t{\n\t\tfor (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)\n\t\t\tvertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImFontConfig\n//-----------------------------------------------------------------------------\n\nImFontConfig::ImFontConfig()\n{\n\tmemset(this, 0, sizeof(*this));\n\tFontDataOwnedByAtlas = true;\n\tOversampleH = 2;\n\tOversampleV = 1;\n\tGlyphMaxAdvanceX = FLT_MAX;\n\tRasterizerMultiply = 1.0f;\n\tEllipsisChar = (ImWchar)-1;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImFontAtlas\n//-----------------------------------------------------------------------------\n\n// A work of art lies ahead! (. = white layer, X = black layer, others are blank)\n// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.\n// (This is used when io.MouseDrawCursor = true)\nconst int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.\nconst int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;\nstatic const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =\n{\n\t\"..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX-     XX          - XX       XX \"\n\t\"..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X-    X..X         -X..X     X..X\"\n\t\"---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X-    X..X         -X...X   X...X\"\n\t\"X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X-    X..X         - X...X X...X \"\n\t\"XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X-    X..X         -  X...X...X  \"\n\t\"X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X-    X..XXX       -   X.....X   \"\n\t\"X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX-    X..X..XXX    -    X...X    \"\n\t\"X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      -    X..X..X..XX  -     X.X     \"\n\t\"X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       -    X..X..X..X.X -    X...X    \"\n\t\"X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        -XXX X..X..X..X..X-   X.....X   \"\n\t\"X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         -X..XX........X..X-  X...X...X  \"\n\t\"X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          -X...X...........X- X...X X...X \"\n\t\"X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           - X..............X-X...X   X...X\"\n\t\"X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            -  X.............X-X..X     X..X\"\n\t\"X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           -  X.............X- XX       XX \"\n\t\"X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          -   X............X--------------\"\n\t\"X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          -   X...........X -             \"\n\t\"X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       -------------------------------------    X..........X -             \"\n\t\"X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           -    X..........X -             \"\n\t\"XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           -     X........X  -             \"\n\t\"      X..X  -       -  X...X  -         X...X         -  X..X           X..X  -           -     X........X  -             \"\n\t\"       XX   -       -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           -     XXXXXXXXXX  -             \"\n\t\"-------------       -    X    -           X           -X.....................X-           -------------------             \"\n\t\"                    ----------------------------------- X...XXXXXXXXXXXXX...X -                                           \"\n\t\"                                                      -  X..X           X..X  -                                           \"\n\t\"                                                      -   X.X           X.X   -                                           \"\n\t\"                                                      -    XX           XX    -                                           \"\n};\n\nstatic const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =\n{\n\t// Pos ........ Size ......... Offset ......\n\t{ ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Arrow\n\t{ ImVec2(13,0), ImVec2(7,16), ImVec2(1, 8) }, // ImGuiMouseCursor_TextInput\n\t{ ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll\n\t{ ImVec2(21,0), ImVec2(9,23), ImVec2(4,11) }, // ImGuiMouseCursor_ResizeNS\n\t{ ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW\n\t{ ImVec2(73,0), ImVec2(17,17), ImVec2(8, 8) }, // ImGuiMouseCursor_ResizeNESW\n\t{ ImVec2(55,0), ImVec2(17,17), ImVec2(8, 8) }, // ImGuiMouseCursor_ResizeNWSE\n\t{ ImVec2(91,0), ImVec2(17,22), ImVec2(5, 0) }, // ImGuiMouseCursor_Hand\n\t{ ImVec2(109,0),ImVec2(13,15), ImVec2(6, 7) }, // ImGuiMouseCursor_NotAllowed\n};\n\nImFontAtlas::ImFontAtlas()\n{\n\tmemset(this, 0, sizeof(*this));\n\tTexGlyphPadding = 1;\n\tPackIdMouseCursors = PackIdLines = -1;\n}\n\nImFontAtlas::~ImFontAtlas()\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tClear();\n}\n\nvoid    ImFontAtlas::ClearInputData()\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tfor (ImFontConfig& font_cfg : ConfigData)\n\t\tif (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)\n\t\t{\n\t\t\tIM_FREE(font_cfg.FontData);\n\t\t\tfont_cfg.FontData = NULL;\n\t\t}\n\n\t// When clearing this we lose access to the font name and other information used to build the font.\n\tfor (ImFont* font : Fonts)\n\t\tif (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)\n\t\t{\n\t\t\tfont->ConfigData = NULL;\n\t\t\tfont->ConfigDataCount = 0;\n\t\t}\n\tConfigData.clear();\n\tCustomRects.clear();\n\tPackIdMouseCursors = PackIdLines = -1;\n\t// Important: we leave TexReady untouched\n}\n\nvoid    ImFontAtlas::ClearTexData()\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tif (TexPixelsAlpha8)\n\t\tIM_FREE(TexPixelsAlpha8);\n\tif (TexPixelsRGBA32)\n\t\tIM_FREE(TexPixelsRGBA32);\n\tTexPixelsAlpha8 = NULL;\n\tTexPixelsRGBA32 = NULL;\n\tTexPixelsUseColors = false;\n\t// Important: we leave TexReady untouched\n}\n\nvoid    ImFontAtlas::ClearFonts()\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tFonts.clear_delete();\n\tTexReady = false;\n}\n\nvoid    ImFontAtlas::Clear()\n{\n\tClearInputData();\n\tClearTexData();\n\tClearFonts();\n}\n\nvoid    ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)\n{\n\t// Build atlas on demand\n\tif (TexPixelsAlpha8 == NULL)\n\t\tBuild();\n\n\t*out_pixels = TexPixelsAlpha8;\n\tif (out_width) *out_width = TexWidth;\n\tif (out_height) *out_height = TexHeight;\n\tif (out_bytes_per_pixel) *out_bytes_per_pixel = 1;\n}\n\nvoid    ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)\n{\n\t// Convert to RGBA32 format on demand\n\t// Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp\n\tif (!TexPixelsRGBA32)\n\t{\n\t\tunsigned char* pixels = NULL;\n\t\tGetTexDataAsAlpha8(&pixels, NULL, NULL);\n\t\tif (pixels)\n\t\t{\n\t\t\tTexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);\n\t\t\tconst unsigned char* src = pixels;\n\t\t\tunsigned int* dst = TexPixelsRGBA32;\n\t\t\tfor (int n = TexWidth * TexHeight; n > 0; n--)\n\t\t\t\t*dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));\n\t\t}\n\t}\n\n\t*out_pixels = (unsigned char*)TexPixelsRGBA32;\n\tif (out_width) *out_width = TexWidth;\n\tif (out_height) *out_height = TexHeight;\n\tif (out_bytes_per_pixel) *out_bytes_per_pixel = 4;\n}\n\nImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tIM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);\n\tIM_ASSERT(font_cfg->SizePixels > 0.0f);\n\n\t// Create new font\n\tif (!font_cfg->MergeMode)\n\t\tFonts.push_back(IM_NEW(ImFont));\n\telse\n\t\tIM_ASSERT(!Fonts.empty() && \"Cannot use MergeMode for the first font\"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.\n\n\tConfigData.push_back(*font_cfg);\n\tImFontConfig& new_font_cfg = ConfigData.back();\n\tif (new_font_cfg.DstFont == NULL)\n\t\tnew_font_cfg.DstFont = Fonts.back();\n\tif (!new_font_cfg.FontDataOwnedByAtlas)\n\t{\n\t\tnew_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);\n\t\tnew_font_cfg.FontDataOwnedByAtlas = true;\n\t\tmemcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);\n\t}\n\n\tif (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)\n\t\tnew_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;\n\n\t// Invalidate texture\n\tTexReady = false;\n\tClearTexData();\n\treturn new_font_cfg.DstFont;\n}\n\n// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)\nstatic unsigned int stb_decompress_length(const unsigned char* input);\nstatic unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);\nstatic const char* GetDefaultCompressedFontDataTTFBase85();\nstatic unsigned int Decode85Byte(char c) { return c >= '\\\\' ? c - 36 : c - 35; }\nstatic void         Decode85(const unsigned char* src, unsigned char* dst)\n{\n\twhile (*src)\n\t{\n\t\tunsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));\n\t\tdst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF);   // We can't assume little-endianness.\n\t\tsrc += 5;\n\t\tdst += 4;\n\t}\n}\n\n// Load embedded ProggyClean.ttf at size 13, disable oversampling\nImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)\n{\n\tImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();\n\tif (!font_cfg_template)\n\t{\n\t\tfont_cfg.OversampleH = font_cfg.OversampleV = 1;\n\t\tfont_cfg.PixelSnapH = true;\n\t}\n\tif (font_cfg.SizePixels <= 0.0f)\n\t\tfont_cfg.SizePixels = 13.0f * 1.0f;\n\tif (font_cfg.Name[0] == '\\0')\n\t\tImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), \"ProggyClean.ttf, %dpx\", (int)font_cfg.SizePixels);\n\tfont_cfg.EllipsisChar = (ImWchar)0x0085;\n\tfont_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f);  // Add +1 offset per 13 units\n\n\tconst char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();\n\tconst ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();\n\tImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges);\n\treturn font;\n}\n\nImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tsize_t data_size = 0;\n\tvoid* data = ImFileLoadToMemory(filename, \"rb\", &data_size, 0);\n\tif (!data)\n\t{\n\t\tIM_ASSERT_USER_ERROR(0, \"Could not load font file!\");\n\t\treturn NULL;\n\t}\n\tImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();\n\tif (font_cfg.Name[0] == '\\0')\n\t{\n\t\t// Store a short copy of filename into into the font name for convenience\n\t\tconst char* p;\n\t\tfor (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\\\'; p--) {}\n\t\tImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), \"%s, %.0fpx\", p, size_pixels);\n\t}\n\treturn AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);\n}\n\n// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().\nImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\tImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();\n\tIM_ASSERT(font_cfg.FontData == NULL);\n\tfont_cfg.FontData = ttf_data;\n\tfont_cfg.FontDataSize = ttf_size;\n\tfont_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;\n\tif (glyph_ranges)\n\t\tfont_cfg.GlyphRanges = glyph_ranges;\n\treturn AddFont(&font_cfg);\n}\n\nImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)\n{\n\tconst unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);\n\tunsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);\n\tstb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);\n\n\tImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();\n\tIM_ASSERT(font_cfg.FontData == NULL);\n\tfont_cfg.FontDataOwnedByAtlas = true;\n\treturn AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);\n}\n\nImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)\n{\n\tint compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;\n\tvoid* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);\n\tDecode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);\n\tImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);\n\tIM_FREE(compressed_ttf);\n\treturn font;\n}\n\nint ImFontAtlas::AddCustomRectRegular(int width, int height)\n{\n\tIM_ASSERT(width > 0 && width <= 0xFFFF);\n\tIM_ASSERT(height > 0 && height <= 0xFFFF);\n\tImFontAtlasCustomRect r;\n\tr.Width = (unsigned short)width;\n\tr.Height = (unsigned short)height;\n\tCustomRects.push_back(r);\n\treturn CustomRects.Size - 1; // Return index\n}\n\nint ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)\n{\n#ifdef IMGUI_USE_WCHAR32\n\tIM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX);\n#endif\n\tIM_ASSERT(font != NULL);\n\tIM_ASSERT(width > 0 && width <= 0xFFFF);\n\tIM_ASSERT(height > 0 && height <= 0xFFFF);\n\tImFontAtlasCustomRect r;\n\tr.Width = (unsigned short)width;\n\tr.Height = (unsigned short)height;\n\tr.GlyphID = id;\n\tr.GlyphAdvanceX = advance_x;\n\tr.GlyphOffset = offset;\n\tr.Font = font;\n\tCustomRects.push_back(r);\n\treturn CustomRects.Size - 1; // Return index\n}\n\nvoid ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const\n{\n\tIM_ASSERT(TexWidth > 0 && TexHeight > 0);   // Font atlas needs to be built before we can calculate UV coordinates\n\tIM_ASSERT(rect->IsPacked());                // Make sure the rectangle has been packed\n\t*out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);\n\t*out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);\n}\n\nbool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])\n{\n\tif (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)\n\t\treturn false;\n\tif (Flags & ImFontAtlasFlags_NoMouseCursors)\n\t\treturn false;\n\n\tIM_ASSERT(PackIdMouseCursors != -1);\n\tImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);\n\tImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);\n\tImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];\n\t*out_size = size;\n\t*out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];\n\tout_uv_border[0] = (pos)*TexUvScale;\n\tout_uv_border[1] = (pos + size) * TexUvScale;\n\tpos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;\n\tout_uv_fill[0] = (pos)*TexUvScale;\n\tout_uv_fill[1] = (pos + size) * TexUvScale;\n\treturn true;\n}\n\nbool    ImFontAtlas::Build()\n{\n\tIM_ASSERT(!Locked && \"Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!\");\n\n\t// Default font is none are specified\n\tif (ConfigData.Size == 0)\n\t\tAddFontDefault();\n\n\t// Select builder\n\t// - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which\n\t//   may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are\n\t//   using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere\n\t//   and point to it instead of pointing directly to return value of the GetBuilderXXX functions.\n\tconst ImFontBuilderIO* builder_io = FontBuilderIO;\n\tif (builder_io == NULL)\n\t{\n#ifdef IMGUI_ENABLE_FREETYPE\n\t\tbuilder_io = ImGuiFreeType::GetBuilderForFreeType();\n#elif defined(IMGUI_ENABLE_STB_TRUETYPE)\n\t\tbuilder_io = ImFontAtlasGetBuilderForStbTruetype();\n#else\n\t\tIM_ASSERT(0); // Invalid Build function\n#endif\n\t}\n\n\t// Build\n\treturn builder_io->FontBuilder_Build(this);\n}\n\nvoid    ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)\n{\n\tfor (unsigned int i = 0; i < 256; i++)\n\t{\n\t\tunsigned int value = (unsigned int)(i * in_brighten_factor);\n\t\tout_table[i] = value > 255 ? 255 : (value & 0xFF);\n\t}\n}\n\nvoid    ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)\n{\n\tIM_ASSERT_PARANOID(w <= stride);\n\tunsigned char* data = pixels + x + y * stride;\n\tfor (int j = h; j > 0; j--, data += stride - w)\n\t\tfor (int i = w; i > 0; i--, data++)\n\t\t\t*data = table[*data];\n}\n\n#ifdef IMGUI_ENABLE_STB_TRUETYPE\n// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)\n// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)\nstruct ImFontBuildSrcData\n{\n\tstbtt_fontinfo      FontInfo;\n\tstbtt_pack_range    PackRange;          // Hold the list of codepoints to pack (essentially points to Codepoints.Data)\n\tstbrp_rect* Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.\n\tstbtt_packedchar* PackedChars;        // Output glyphs\n\tconst ImWchar* SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)\n\tint                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]\n\tint                 GlyphsHighest;      // Highest requested codepoint\n\tint                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)\n\tImBitVector         GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)\n\tImVector<int>       GlyphsList;         // Glyph codepoints list (flattened version of GlyphsSet)\n};\n\n// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)\nstruct ImFontBuildDstData\n{\n\tint                 SrcCount;           // Number of source fonts targeting this destination font.\n\tint                 GlyphsHighest;\n\tint                 GlyphsCount;\n\tImBitVector         GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.\n};\n\nstatic void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>* out)\n{\n\tIM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));\n\tconst ImU32* it_begin = in->Storage.begin();\n\tconst ImU32* it_end = in->Storage.end();\n\tfor (const ImU32* it = it_begin; it < it_end; it++)\n\t\tif (ImU32 entries_32 = *it)\n\t\t\tfor (ImU32 bit_n = 0; bit_n < 32; bit_n++)\n\t\t\t\tif (entries_32 & ((ImU32)1 << bit_n))\n\t\t\t\t\tout->push_back((int)(((it - it_begin) << 5) + bit_n));\n}\n\nstatic bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)\n{\n\tIM_ASSERT(atlas->ConfigData.Size > 0);\n\n\tImFontAtlasBuildInit(atlas);\n\n\t// Clear atlas\n\tatlas->TexID = (ImTextureID)NULL;\n\tatlas->TexWidth = atlas->TexHeight = 0;\n\tatlas->TexUvScale = ImVec2(0.0f, 0.0f);\n\tatlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);\n\tatlas->ClearTexData();\n\n\t// Temporary storage for building\n\tImVector<ImFontBuildSrcData> src_tmp_array;\n\tImVector<ImFontBuildDstData> dst_tmp_array;\n\tsrc_tmp_array.resize(atlas->ConfigData.Size);\n\tdst_tmp_array.resize(atlas->Fonts.Size);\n\tmemset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());\n\tmemset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());\n\n\t// 1. Initialize font loading structure, check font data validity\n\tfor (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)\n\t{\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tIM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));\n\n\t\t// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)\n\t\tsrc_tmp.DstIndex = -1;\n\t\tfor (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)\n\t\t\tif (cfg.DstFont == atlas->Fonts[output_i])\n\t\t\t\tsrc_tmp.DstIndex = output_i;\n\t\tif (src_tmp.DstIndex == -1)\n\t\t{\n\t\t\tIM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?\n\t\t\treturn false;\n\t\t}\n\t\t// Initialize helper structure for font loading and verify that the TTF/OTF data is correct\n\t\tconst int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);\n\t\tIM_ASSERT(font_offset >= 0 && \"FontData is incorrect, or FontNo cannot be found.\");\n\t\tif (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))\n\t\t\treturn false;\n\n\t\t// Measure highest codepoints\n\t\tImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];\n\t\tsrc_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();\n\t\tfor (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)\n\t\t{\n\t\t\t// Check for valid range. This may also help detect *some* dangling pointers, because a common\n\t\t\t// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.\n\t\t\tIM_ASSERT(src_range[0] <= src_range[1]);\n\t\t\tsrc_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);\n\t\t}\n\t\tdst_tmp.SrcCount++;\n\t\tdst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);\n\t}\n\n\t// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.\n\tint total_glyphs_count = 0;\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];\n\t\tsrc_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);\n\t\tif (dst_tmp.GlyphsSet.Storage.empty())\n\t\t\tdst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);\n\n\t\tfor (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)\n\t\t\tfor (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)\n\t\t\t{\n\t\t\t\tif (dst_tmp.GlyphsSet.TestBit(codepoint))    // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint))    // It is actually in the font?\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Add to avail set/counters\n\t\t\t\tsrc_tmp.GlyphsCount++;\n\t\t\t\tdst_tmp.GlyphsCount++;\n\t\t\t\tsrc_tmp.GlyphsSet.SetBit(codepoint);\n\t\t\t\tdst_tmp.GlyphsSet.SetBit(codepoint);\n\t\t\t\ttotal_glyphs_count++;\n\t\t\t}\n\t}\n\n\t// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tsrc_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);\n\t\tUnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);\n\t\tsrc_tmp.GlyphsSet.Clear();\n\t\tIM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);\n\t}\n\tfor (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)\n\t\tdst_tmp_array[dst_i].GlyphsSet.Clear();\n\tdst_tmp_array.clear();\n\n\t// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)\n\t// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)\n\tImVector<stbrp_rect> buf_rects;\n\tImVector<stbtt_packedchar> buf_packedchars;\n\tbuf_rects.resize(total_glyphs_count);\n\tbuf_packedchars.resize(total_glyphs_count);\n\tmemset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());\n\tmemset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());\n\n\t// 4. Gather glyphs sizes so we can pack them in our virtual canvas.\n\tint total_surface = 0;\n\tint buf_rects_out_n = 0;\n\tint buf_packedchars_out_n = 0;\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\tsrc_tmp.Rects = &buf_rects[buf_rects_out_n];\n\t\tsrc_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];\n\t\tbuf_rects_out_n += src_tmp.GlyphsCount;\n\t\tbuf_packedchars_out_n += src_tmp.GlyphsCount;\n\n\t\t// Convert our ranges in the format stb_truetype wants\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tsrc_tmp.PackRange.font_size = cfg.SizePixels;\n\t\tsrc_tmp.PackRange.first_unicode_codepoint_in_range = 0;\n\t\tsrc_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;\n\t\tsrc_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;\n\t\tsrc_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;\n\t\tsrc_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;\n\t\tsrc_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;\n\n\t\t// Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)\n\t\tconst float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);\n\t\tconst int padding = atlas->TexGlyphPadding;\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)\n\t\t{\n\t\t\tint x0, y0, x1, y1;\n\t\t\tconst int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);\n\t\t\tIM_ASSERT(glyph_index_in_font != 0);\n\t\t\tstbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);\n\t\t\tsrc_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);\n\t\t\tsrc_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);\n\t\t\ttotal_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;\n\t\t}\n\t}\n\n\t// We need a width for the skyline algorithm, any width!\n\t// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.\n\t// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.\n\tconst int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;\n\tatlas->TexHeight = 0;\n\tif (atlas->TexDesiredWidth > 0)\n\t\tatlas->TexWidth = atlas->TexDesiredWidth;\n\telse\n\t\tatlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;\n\n\t// 5. Start packing\n\t// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).\n\tconst int TEX_HEIGHT_MAX = 1024 * 32;\n\tstbtt_pack_context spc = {};\n\tstbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);\n\tImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);\n\n\t// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\tstbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);\n\n\t\t// Extend texture height and mark missing glyphs as non-packed so we won't render them.\n\t\t// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)\n\t\t\tif (src_tmp.Rects[glyph_i].was_packed)\n\t\t\t\tatlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);\n\t}\n\n\t// 7. Allocate texture\n\tatlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);\n\tatlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);\n\tatlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);\n\tmemset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);\n\tspc.pixels = atlas->TexPixelsAlpha8;\n\tspc.height = atlas->TexHeight;\n\n\t// 8. Render/rasterize font characters into the texture\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\tstbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);\n\n\t\t// Apply multiply operator\n\t\tif (cfg.RasterizerMultiply != 1.0f)\n\t\t{\n\t\t\tunsigned char multiply_table[256];\n\t\t\tImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);\n\t\t\tstbrp_rect* r = &src_tmp.Rects[0];\n\t\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)\n\t\t\t\tif (r->was_packed)\n\t\t\t\t\tImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);\n\t\t}\n\t\tsrc_tmp.Rects = NULL;\n\t}\n\n\t// End packing\n\tstbtt_PackEnd(&spc);\n\tbuf_rects.clear();\n\n\t// 9. Setup ImFont and glyphs for runtime\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\t// When merging fonts with MergeMode=true:\n\t\t// - We can have multiple input fonts writing into a same destination font.\n\t\t// - dst_font->ConfigData is != from cfg which is our source configuration.\n\t\tImFontBuildSrcData& src_tmp = src_tmp_array[src_i];\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tImFont* dst_font = cfg.DstFont;\n\n\t\tconst float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);\n\t\tint unscaled_ascent, unscaled_descent, unscaled_line_gap;\n\t\tstbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);\n\n\t\tconst float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));\n\t\tconst float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));\n\t\tImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);\n\t\tconst float font_off_x = cfg.GlyphOffset.x;\n\t\tconst float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);\n\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)\n\t\t{\n\t\t\t// Register glyph\n\t\t\tconst int codepoint = src_tmp.GlyphsList[glyph_i];\n\t\t\tconst stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];\n\t\t\tstbtt_aligned_quad q;\n\t\t\tfloat unused_x = 0.0f, unused_y = 0.0f;\n\t\t\tstbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0);\n\t\t\tdst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);\n\t\t}\n\t}\n\n\t// Cleanup\n\tsrc_tmp_array.clear_destruct();\n\n\tImFontAtlasBuildFinish(atlas);\n\treturn true;\n}\n\nconst ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()\n{\n\tstatic ImFontBuilderIO io;\n\tio.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype;\n\treturn &io;\n}\n\n#endif // IMGUI_ENABLE_STB_TRUETYPE\n\nvoid ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)\n{\n\tif (!font_config->MergeMode)\n\t{\n\t\tfont->ClearOutputData();\n\t\tfont->FontSize = font_config->SizePixels;\n\t\tfont->ConfigData = font_config;\n\t\tfont->ConfigDataCount = 0;\n\t\tfont->ContainerAtlas = atlas;\n\t\tfont->Ascent = ascent;\n\t\tfont->Descent = descent;\n\t}\n\tfont->ConfigDataCount++;\n}\n\nvoid ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)\n{\n\tstbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;\n\tIM_ASSERT(pack_context != NULL);\n\n\tImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;\n\tIM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.\n#ifdef __GNUC__\n\tif (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343)\n#endif\n\n\tImVector<stbrp_rect> pack_rects;\n\tpack_rects.resize(user_rects.Size);\n\tmemset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());\n\tfor (int i = 0; i < user_rects.Size; i++)\n\t{\n\t\tpack_rects[i].w = user_rects[i].Width;\n\t\tpack_rects[i].h = user_rects[i].Height;\n\t}\n\tstbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);\n\tfor (int i = 0; i < pack_rects.Size; i++)\n\t\tif (pack_rects[i].was_packed)\n\t\t{\n\t\t\tuser_rects[i].X = (unsigned short)pack_rects[i].x;\n\t\t\tuser_rects[i].Y = (unsigned short)pack_rects[i].y;\n\t\t\tIM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);\n\t\t\tatlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);\n\t\t}\n}\n\nvoid ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value)\n{\n\tIM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);\n\tIM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);\n\tunsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth);\n\tfor (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)\n\t\tfor (int off_x = 0; off_x < w; off_x++)\n\t\t\tout_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00;\n}\n\nvoid ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value)\n{\n\tIM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);\n\tIM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);\n\tunsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth);\n\tfor (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)\n\t\tfor (int off_x = 0; off_x < w; off_x++)\n\t\t\tout_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS;\n}\n\nstatic void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)\n{\n\tImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);\n\tIM_ASSERT(r->IsPacked());\n\n\tconst int w = atlas->TexWidth;\n\tif (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))\n\t{\n\t\t// Render/copy pixels\n\t\tIM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);\n\t\tconst int x_for_white = r->X;\n\t\tconst int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;\n\t\tif (atlas->TexPixelsAlpha8 != NULL)\n\t\t{\n\t\t\tImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF);\n\t\t\tImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE);\n\t\t\tImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Render 4 white pixels\n\t\tIM_ASSERT(r->Width == 2 && r->Height == 2);\n\t\tconst int offset = (int)r->X + (int)r->Y * w;\n\t\tif (atlas->TexPixelsAlpha8 != NULL)\n\t\t{\n\t\t\tatlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tatlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE;\n\t\t}\n\t}\n\tatlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y);\n}\n\nstatic void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)\n{\n\tif (atlas->Flags & ImFontAtlasFlags_NoBakedLines)\n\t\treturn;\n\n\t// This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them\n\tImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines);\n\tIM_ASSERT(r->IsPacked());\n\tfor (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row\n\t{\n\t\t// Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle\n\t\tunsigned int y = n;\n\t\tunsigned int line_width = n;\n\t\tunsigned int pad_left = (r->Width - line_width) / 2;\n\t\tunsigned int pad_right = r->Width - (pad_left + line_width);\n\n\t\t// Write each slice\n\t\tIM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels\n\t\tif (atlas->TexPixelsAlpha8 != NULL)\n\t\t{\n\t\t\tunsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)];\n\t\t\tfor (unsigned int i = 0; i < pad_left; i++)\n\t\t\t\t*(write_ptr + i) = 0x00;\n\n\t\t\tfor (unsigned int i = 0; i < line_width; i++)\n\t\t\t\t*(write_ptr + pad_left + i) = 0xFF;\n\n\t\t\tfor (unsigned int i = 0; i < pad_right; i++)\n\t\t\t\t*(write_ptr + pad_left + line_width + i) = 0x00;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tunsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)];\n\t\t\tfor (unsigned int i = 0; i < pad_left; i++)\n\t\t\t\t*(write_ptr + i) = IM_COL32(255, 255, 255, 0);\n\n\t\t\tfor (unsigned int i = 0; i < line_width; i++)\n\t\t\t\t*(write_ptr + pad_left + i) = IM_COL32_WHITE;\n\n\t\t\tfor (unsigned int i = 0; i < pad_right; i++)\n\t\t\t\t*(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0);\n\t\t}\n\n\t\t// Calculate UVs for this line\n\t\tImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale;\n\t\tImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale;\n\t\tfloat half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts\n\t\tatlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);\n\t}\n}\n\n// Note: this is called / shared by both the stb_truetype and the FreeType builder\nvoid ImFontAtlasBuildInit(ImFontAtlas* atlas)\n{\n\t// Register texture region for mouse cursors or standard white pixels\n\tif (atlas->PackIdMouseCursors < 0)\n\t{\n\t\tif (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))\n\t\t\tatlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);\n\t\telse\n\t\t\tatlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);\n\t}\n\n\t// Register texture region for thick lines\n\t// The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row\n\tif (atlas->PackIdLines < 0)\n\t{\n\t\tif (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines))\n\t\t\tatlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);\n\t}\n}\n\n// This is called/shared by both the stb_truetype and the FreeType builder.\nvoid ImFontAtlasBuildFinish(ImFontAtlas* atlas)\n{\n\t// Render into our custom data blocks\n\tIM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL);\n\tImFontAtlasBuildRenderDefaultTexData(atlas);\n\tImFontAtlasBuildRenderLinesTexData(atlas);\n\n\t// Register custom rectangle glyphs\n\tfor (int i = 0; i < atlas->CustomRects.Size; i++)\n\t{\n\t\tconst ImFontAtlasCustomRect* r = &atlas->CustomRects[i];\n\t\tif (r->Font == NULL || r->GlyphID == 0)\n\t\t\tcontinue;\n\n\t\t// Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH\n\t\tIM_ASSERT(r->Font->ContainerAtlas == atlas);\n\t\tImVec2 uv0, uv1;\n\t\tatlas->CalcCustomRectUV(r, &uv0, &uv1);\n\t\tr->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX);\n\t}\n\n\t// Build all fonts lookup tables\n\tfor (ImFont* font : atlas->Fonts)\n\t\tif (font->DirtyLookupTables)\n\t\t\tfont->BuildLookupTable();\n\n\tatlas->TexReady = true;\n}\n\n// Retrieve list of range (2 int per range, values are inclusive)\nconst ImWchar* ImFontAtlas::GetGlyphRangesDefault()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesGreek()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x0370, 0x03FF, // Greek and Coptic\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesKorean()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x3131, 0x3163, // Korean alphabets\n\t\t0xAC00, 0xD7A3, // Korean characters\n\t\t0xFFFD, 0xFFFD, // Invalid\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x2000, 0x206F, // General Punctuation\n\t\t0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana\n\t\t0x31F0, 0x31FF, // Katakana Phonetic Extensions\n\t\t0xFF00, 0xFFEF, // Half-width characters\n\t\t0xFFFD, 0xFFFD, // Invalid\n\t\t0x4e00, 0x9FAF, // CJK Ideograms\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nstatic void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges)\n{\n\tfor (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)\n\t{\n\t\tout_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);\n\t\tbase_codepoint += accumulative_offsets[n];\n\t}\n\tout_ranges[0] = 0;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] ImFontAtlas glyph ranges helpers\n//-------------------------------------------------------------------------\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()\n{\n\t// Store 2500 regularly used characters for Simplified Chinese.\n\t// Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8\n\t// This table covers 97.97% of all characters used during the month in July, 1987.\n\t// You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.\n\t// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)\n\tstatic const short accumulative_offsets_from_0x4E00[] =\n\t{\n\t\t0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2,\n\t\t1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4,\n\t\t2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1,\n\t\t1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2,\n\t\t3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6,\n\t\t1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1,\n\t\t1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3,\n\t\t2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4,\n\t\t27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12,\n\t\t3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1,\n\t\t1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23,\n\t\t176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6,\n\t\t5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6,\n\t\t1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1,\n\t\t6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5,\n\t\t2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15,\n\t\t2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6,\n\t\t2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4,\n\t\t3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5,\n\t\t3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2,\n\t\t3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16,\n\t\t1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31,\n\t\t140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7,\n\t\t5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2,\n\t\t2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13,\n\t\t4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3,\n\t\t2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4,\n\t\t4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1,\n\t\t3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3,\n\t\t3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11,\n\t\t2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9,\n\t\t5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2,\n\t\t3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3,\n\t\t1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12,\n\t\t4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8,\n\t\t4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5,\n\t\t26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1,\n\t\t3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5,\n\t\t2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6,\n\t\t10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6\n\t};\n\tstatic ImWchar base_ranges[] = // not zero-terminated\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x2000, 0x206F, // General Punctuation\n\t\t0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana\n\t\t0x31F0, 0x31FF, // Katakana Phonetic Extensions\n\t\t0xFF00, 0xFFEF, // Half-width characters\n\t\t0xFFFD, 0xFFFD  // Invalid\n\t};\n\tstatic ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };\n\tif (!full_ranges[0])\n\t{\n\t\tmemcpy(full_ranges, base_ranges, sizeof(base_ranges));\n\t\tUnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));\n\t}\n\treturn &full_ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesJapanese()\n{\n\t// 2999 ideograms code points for Japanese\n\t// - 2136 Joyo (meaning \"for regular use\" or \"for common use\") Kanji code points\n\t// - 863 Jinmeiyo (meaning \"for personal name\") Kanji code points\n\t// - Sourced from official information provided by the government agencies of Japan:\n\t//   - List of Joyo Kanji by the Agency for Cultural Affairs\n\t//     - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/\n\t//   - List of Jinmeiyo Kanji by the Ministry of Justice\n\t//     - http://www.moj.go.jp/MINJI/minji86.html\n\t//   - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).\n\t//     - https://creativecommons.org/licenses/by/4.0/legalcode\n\t// - You can generate this code by the script at:\n\t//   - https://github.com/vaiorabbit/everyday_use_kanji\n\t// - References:\n\t//   - List of Joyo Kanji\n\t//     - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji\n\t//   - List of Jinmeiyo Kanji\n\t//     - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji\n\t// - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.\n\t// You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.\n\t// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)\n\tstatic const short accumulative_offsets_from_0x4E00[] =\n\t{\n\t\t0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1,\n\t\t1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3,\n\t\t2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8,\n\t\t2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5,\n\t\t2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1,\n\t\t1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30,\n\t\t2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3,\n\t\t13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4,\n\t\t5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14,\n\t\t2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1,\n\t\t1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1,\n\t\t7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1,\n\t\t1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1,\n\t\t6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2,\n\t\t10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7,\n\t\t2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5,\n\t\t3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1,\n\t\t6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7,\n\t\t4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2,\n\t\t4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5,\n\t\t1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6,\n\t\t12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2,\n\t\t1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16,\n\t\t22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11,\n\t\t2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18,\n\t\t18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9,\n\t\t14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3,\n\t\t1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6,\n\t\t40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1,\n\t\t12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8,\n\t\t2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1,\n\t\t1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10,\n\t\t1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5,\n\t\t3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2,\n\t\t14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5,\n\t\t12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1,\n\t\t2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5,\n\t\t1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4,\n\t\t3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7,\n\t\t2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5,\n\t\t13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13,\n\t\t18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21,\n\t\t37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1,\n\t\t5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38,\n\t\t32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4,\n\t\t1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4,\n\t\t4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,\n\t\t3,2,1,1,1,1,2,1,1,\n\t};\n\tstatic ImWchar base_ranges[] = // not zero-terminated\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana\n\t\t0x31F0, 0x31FF, // Katakana Phonetic Extensions\n\t\t0xFF00, 0xFFEF, // Half-width characters\n\t\t0xFFFD, 0xFFFD  // Invalid\n\t};\n\tstatic ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };\n\tif (!full_ranges[0])\n\t{\n\t\tmemcpy(full_ranges, base_ranges, sizeof(base_ranges));\n\t\tUnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));\n\t}\n\treturn &full_ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin + Latin Supplement\n\t\t0x0400, 0x052F, // Cyrillic + Cyrillic Supplement\n\t\t0x2DE0, 0x2DFF, // Cyrillic Extended-A\n\t\t0xA640, 0xA69F, // Cyrillic Extended-B\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesThai()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin\n\t\t0x2010, 0x205E, // Punctuations\n\t\t0x0E00, 0x0E7F, // Thai\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\nconst ImWchar* ImFontAtlas::GetGlyphRangesVietnamese()\n{\n\tstatic const ImWchar ranges[] =\n\t{\n\t\t0x0020, 0x00FF, // Basic Latin\n\t\t0x0102, 0x0103,\n\t\t0x0110, 0x0111,\n\t\t0x0128, 0x0129,\n\t\t0x0168, 0x0169,\n\t\t0x01A0, 0x01A1,\n\t\t0x01AF, 0x01B0,\n\t\t0x1EA0, 0x1EF9,\n\t\t0,\n\t};\n\treturn &ranges[0];\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImFontGlyphRangesBuilder\n//-----------------------------------------------------------------------------\n\nvoid ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)\n{\n\twhile (text_end ? (text < text_end) : *text)\n\t{\n\t\tunsigned int c = 0;\n\t\tint c_len = ImTextCharFromUtf8(&c, text, text_end);\n\t\ttext += c_len;\n\t\tif (c_len == 0)\n\t\t\tbreak;\n\t\tAddChar((ImWchar)c);\n\t}\n}\n\nvoid ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)\n{\n\tfor (; ranges[0]; ranges += 2)\n\t\tfor (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560\n\t\t\tAddChar((ImWchar)c);\n}\n\nvoid ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)\n{\n\tconst int max_codepoint = IM_UNICODE_CODEPOINT_MAX;\n\tfor (int n = 0; n <= max_codepoint; n++)\n\t\tif (GetBit(n))\n\t\t{\n\t\t\tout_ranges->push_back((ImWchar)n);\n\t\t\twhile (n < max_codepoint && GetBit(n + 1))\n\t\t\t\tn++;\n\t\t\tout_ranges->push_back((ImWchar)n);\n\t\t}\n\tout_ranges->push_back(0);\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImFont\n//-----------------------------------------------------------------------------\n\nImFont::ImFont()\n{\n\tFontSize = 0.0f;\n\tFallbackAdvanceX = 0.0f;\n\tFallbackChar = (ImWchar)-1;\n\tEllipsisChar = (ImWchar)-1;\n\tEllipsisWidth = EllipsisCharStep = 0.0f;\n\tEllipsisCharCount = 0;\n\tFallbackGlyph = NULL;\n\tContainerAtlas = NULL;\n\tConfigData = NULL;\n\tConfigDataCount = 0;\n\tDirtyLookupTables = false;\n\tScale = 1.0f;\n\tAscent = Descent = 0.0f;\n\tMetricsTotalSurface = 0;\n\tmemset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));\n}\n\nImFont::~ImFont()\n{\n\tClearOutputData();\n}\n\nvoid    ImFont::ClearOutputData()\n{\n\tFontSize = 0.0f;\n\tFallbackAdvanceX = 0.0f;\n\tGlyphs.clear();\n\tIndexAdvanceX.clear();\n\tIndexLookup.clear();\n\tFallbackGlyph = NULL;\n\tContainerAtlas = NULL;\n\tDirtyLookupTables = true;\n\tAscent = Descent = 0.0f;\n\tMetricsTotalSurface = 0;\n}\n\nstatic ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)\n{\n\tfor (int n = 0; n < candidate_chars_count; n++)\n\t\tif (font->FindGlyphNoFallback(candidate_chars[n]) != NULL)\n\t\t\treturn candidate_chars[n];\n\treturn (ImWchar)-1;\n}\n\nvoid ImFont::BuildLookupTable()\n{\n\tint max_codepoint = 0;\n\tfor (int i = 0; i != Glyphs.Size; i++)\n\t\tmax_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);\n\n\t// Build lookup table\n\tIM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved\n\tIndexAdvanceX.clear();\n\tIndexLookup.clear();\n\tDirtyLookupTables = false;\n\tmemset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));\n\tGrowIndex(max_codepoint + 1);\n\tfor (int i = 0; i < Glyphs.Size; i++)\n\t{\n\t\tint codepoint = (int)Glyphs[i].Codepoint;\n\t\tIndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;\n\t\tIndexLookup[codepoint] = (ImWchar)i;\n\n\t\t// Mark 4K page as used\n\t\tconst int page_n = codepoint / 4096;\n\t\tUsed4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);\n\t}\n\n\t// Create a glyph to handle TAB\n\t// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at \"column 0\" ?)\n\tif (FindGlyph((ImWchar)' '))\n\t{\n\t\tif (Glyphs.back().Codepoint != '\\t')   // So we can call this function multiple times (FIXME: Flaky)\n\t\t\tGlyphs.resize(Glyphs.Size + 1);\n\t\tImFontGlyph& tab_glyph = Glyphs.back();\n\t\ttab_glyph = *FindGlyph((ImWchar)' ');\n\t\ttab_glyph.Codepoint = '\\t';\n\t\ttab_glyph.AdvanceX *= IM_TABSIZE;\n\t\tIndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;\n\t\tIndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1);\n\t}\n\n\t// Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)\n\tSetGlyphVisible((ImWchar)' ', false);\n\tSetGlyphVisible((ImWchar)'\\t', false);\n\n\t// Setup Fallback character\n\tconst ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };\n\tFallbackGlyph = FindGlyphNoFallback(FallbackChar);\n\tif (FallbackGlyph == NULL)\n\t{\n\t\tFallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars));\n\t\tFallbackGlyph = FindGlyphNoFallback(FallbackChar);\n\t\tif (FallbackGlyph == NULL)\n\t\t{\n\t\t\tFallbackGlyph = &Glyphs.back();\n\t\t\tFallbackChar = (ImWchar)FallbackGlyph->Codepoint;\n\t\t}\n\t}\n\tFallbackAdvanceX = FallbackGlyph->AdvanceX;\n\tfor (int i = 0; i < max_codepoint + 1; i++)\n\t\tif (IndexAdvanceX[i] < 0.0f)\n\t\t\tIndexAdvanceX[i] = FallbackAdvanceX;\n\n\t// Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).\n\t// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.\n\t// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.\n\tconst ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };\n\tconst ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };\n\tif (EllipsisChar == (ImWchar)-1)\n\t\tEllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));\n\tconst ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));\n\tif (EllipsisChar != (ImWchar)-1)\n\t{\n\t\tEllipsisCharCount = 1;\n\t\tEllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1;\n\t}\n\telse if (dot_char != (ImWchar)-1)\n\t{\n\t\tconst ImFontGlyph* glyph = FindGlyph(dot_char);\n\t\tEllipsisChar = dot_char;\n\t\tEllipsisCharCount = 3;\n\t\tEllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f;\n\t\tEllipsisWidth = EllipsisCharStep * 3.0f - 1.0f;\n\t}\n}\n\n// API is designed this way to avoid exposing the 4K page size\n// e.g. use with IsGlyphRangeUnused(0, 255)\nbool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)\n{\n\tunsigned int page_begin = (c_begin / 4096);\n\tunsigned int page_last = (c_last / 4096);\n\tfor (unsigned int page_n = page_begin; page_n <= page_last; page_n++)\n\t\tif ((page_n >> 3) < sizeof(Used4kPagesMap))\n\t\t\tif (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))\n\t\t\t\treturn false;\n\treturn true;\n}\n\nvoid ImFont::SetGlyphVisible(ImWchar c, bool visible)\n{\n\tif (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))\n\t\tglyph->Visible = visible ? 1 : 0;\n}\n\nvoid ImFont::GrowIndex(int new_size)\n{\n\tIM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);\n\tif (new_size <= IndexLookup.Size)\n\t\treturn;\n\tIndexAdvanceX.resize(new_size, -1.0f);\n\tIndexLookup.resize(new_size, (ImWchar)-1);\n}\n\n// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.\n// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).\n// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.\nvoid ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)\n{\n\tif (cfg != NULL)\n\t{\n\t\t// Clamp & recenter if needed\n\t\tconst float advance_x_original = advance_x;\n\t\tadvance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);\n\t\tif (advance_x != advance_x_original)\n\t\t{\n\t\t\tfloat char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;\n\t\t\tx0 += char_off_x;\n\t\t\tx1 += char_off_x;\n\t\t}\n\n\t\t// Snap to pixel\n\t\tif (cfg->PixelSnapH)\n\t\t\tadvance_x = IM_ROUND(advance_x);\n\n\t\t// Bake spacing\n\t\tadvance_x += cfg->GlyphExtraSpacing.x;\n\t}\n\n\tGlyphs.resize(Glyphs.Size + 1);\n\tImFontGlyph& glyph = Glyphs.back();\n\tglyph.Codepoint = (unsigned int)codepoint;\n\tglyph.Visible = (x0 != x1) && (y0 != y1);\n\tglyph.Colored = false;\n\tglyph.X0 = x0;\n\tglyph.Y0 = y0;\n\tglyph.X1 = x1;\n\tglyph.Y1 = y1;\n\tglyph.U0 = u0;\n\tglyph.V0 = v0;\n\tglyph.U1 = u1;\n\tglyph.V1 = v1;\n\tglyph.AdvanceX = advance_x;\n\n\t// Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)\n\t// We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling.\n\tfloat pad = ContainerAtlas->TexGlyphPadding + 0.99f;\n\tDirtyLookupTables = true;\n\tMetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad);\n}\n\nvoid ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)\n{\n\tIM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.\n\tunsigned int index_size = (unsigned int)IndexLookup.Size;\n\n\tif (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists\n\t\treturn;\n\tif (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op\n\t\treturn;\n\n\tGrowIndex(dst + 1);\n\tIndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;\n\tIndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;\n}\n\nconst ImFontGlyph* ImFont::FindGlyph(ImWchar c) const\n{\n\tif (c >= (size_t)IndexLookup.Size)\n\t\treturn FallbackGlyph;\n\tconst ImWchar i = IndexLookup.Data[c];\n\tif (i == (ImWchar)-1)\n\t\treturn FallbackGlyph;\n\treturn &Glyphs.Data[i];\n}\n\nconst ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const\n{\n\tif (c >= (size_t)IndexLookup.Size)\n\t\treturn NULL;\n\tconst ImWchar i = IndexLookup.Data[c];\n\tif (i == (ImWchar)-1)\n\t\treturn NULL;\n\treturn &Glyphs.Data[i];\n}\n\n// Wrapping skips upcoming blanks\nstatic inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)\n{\n\twhile (text < text_end && ImCharIsBlankA(*text))\n\t\ttext++;\n\tif (*text == '\\n')\n\t\ttext++;\n\treturn text;\n}\n\n// Simple word-wrapping for English, not full-featured. Please submit failing cases!\n// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.\n// FIXME: Much possible improvements (don't cut things like \"word !\", \"word!!!\" but cut within \"word,,,,\", more sensible support for punctuations, support for Unicode punctuations, etc.)\nconst char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const\n{\n\t// For references, possible wrap point marked with ^\n\t//  \"aaa bbb, ccc,ddd. eee   fff. ggg!\"\n\t//      ^    ^    ^   ^   ^__    ^    ^\n\n\t// List of hardcoded separators: .,;!?'\"\n\n\t// Skip extra blanks after a line returns (that includes not counting them in width computation)\n\t// e.g. \"Hello    world\" --> \"Hello\" \"World\"\n\n\t// Cut words that cannot possibly fit within one line.\n\t// e.g.: \"The tropical fish\" with ~5 characters worth of width --> \"The tr\" \"opical\" \"fish\"\n\tfloat line_width = 0.0f;\n\tfloat word_width = 0.0f;\n\tfloat blank_width = 0.0f;\n\twrap_width /= scale; // We work with unscaled widths to avoid scaling every characters\n\n\tconst char* word_end = text;\n\tconst char* prev_word_end = NULL;\n\tbool inside_word = true;\n\n\tconst char* s = text;\n\tIM_ASSERT(text_end != NULL);\n\twhile (s < text_end)\n\t{\n\t\tunsigned int c = (unsigned int)*s;\n\t\tconst char* next_s;\n\t\tif (c < 0x80)\n\t\t\tnext_s = s + 1;\n\t\telse\n\t\t\tnext_s = s + ImTextCharFromUtf8(&c, s, text_end);\n\n\t\tif (c < 32)\n\t\t{\n\t\t\tif (c == '\\n')\n\t\t\t{\n\t\t\t\tline_width = word_width = blank_width = 0.0f;\n\t\t\t\tinside_word = true;\n\t\t\t\ts = next_s;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c == '\\r')\n\t\t\t{\n\t\t\t\ts = next_s;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tconst float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);\n\t\tif (ImCharIsBlankW(c))\n\t\t{\n\t\t\tif (inside_word)\n\t\t\t{\n\t\t\t\tline_width += blank_width;\n\t\t\t\tblank_width = 0.0f;\n\t\t\t\tword_end = s;\n\t\t\t}\n\t\t\tblank_width += char_width;\n\t\t\tinside_word = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tword_width += char_width;\n\t\t\tif (inside_word)\n\t\t\t{\n\t\t\t\tword_end = next_s;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tprev_word_end = word_end;\n\t\t\t\tline_width += word_width + blank_width;\n\t\t\t\tword_width = blank_width = 0.0f;\n\t\t\t}\n\n\t\t\t// Allow wrapping after punctuation.\n\t\t\tinside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\\\"');\n\t\t}\n\n\t\t// We ignore blank width at the end of the line (they can be skipped)\n\t\tif (line_width + word_width > wrap_width)\n\t\t{\n\t\t\t// Words that cannot possibly fit within an entire line will be cut anywhere.\n\t\t\tif (word_width < wrap_width)\n\t\t\t\ts = prev_word_end ? prev_word_end : word_end;\n\t\t\tbreak;\n\t\t}\n\n\t\ts = next_s;\n\t}\n\n\t// Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.\n\t// +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).\n\tif (s == text && text < text_end)\n\t\treturn s + 1;\n\treturn s;\n}\n\nImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const\n{\n\tif (!text_end)\n\t\ttext_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.\n\n\tconst float line_height = size;\n\tconst float scale = size / FontSize;\n\n\tImVec2 text_size = ImVec2(0, 0);\n\tfloat line_width = 0.0f;\n\n\tconst bool word_wrap_enabled = (wrap_width > 0.0f);\n\tconst char* word_wrap_eol = NULL;\n\n\tconst char* s = text_begin;\n\twhile (s < text_end)\n\t{\n\t\tif (word_wrap_enabled)\n\t\t{\n\t\t\t// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.\n\t\t\tif (!word_wrap_eol)\n\t\t\t\tword_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);\n\n\t\t\tif (s >= word_wrap_eol)\n\t\t\t{\n\t\t\t\tif (text_size.x < line_width)\n\t\t\t\t\ttext_size.x = line_width;\n\t\t\t\ttext_size.y += line_height;\n\t\t\t\tline_width = 0.0f;\n\t\t\t\tword_wrap_eol = NULL;\n\t\t\t\ts = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Decode and advance source\n\t\tconst char* prev_s = s;\n\t\tunsigned int c = (unsigned int)*s;\n\t\tif (c < 0x80)\n\t\t\ts += 1;\n\t\telse\n\t\t\ts += ImTextCharFromUtf8(&c, s, text_end);\n\n\t\tif (c < 32)\n\t\t{\n\t\t\tif (c == '\\n')\n\t\t\t{\n\t\t\t\ttext_size.x = ImMax(text_size.x, line_width);\n\t\t\t\ttext_size.y += line_height;\n\t\t\t\tline_width = 0.0f;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c == '\\r')\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tconst float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;\n\t\tif (line_width + char_width >= max_width)\n\t\t{\n\t\t\ts = prev_s;\n\t\t\tbreak;\n\t\t}\n\n\t\tline_width += char_width;\n\t}\n\n\tif (text_size.x < line_width)\n\t\ttext_size.x = line_width;\n\n\tif (line_width > 0 || text_size.y == 0.0f)\n\t\ttext_size.y += line_height;\n\n\tif (remaining)\n\t\t*remaining = s;\n\n\treturn text_size;\n}\n\n// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.\nvoid ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const\n{\n\tconst ImFontGlyph* glyph = FindGlyph(c);\n\tif (!glyph || !glyph->Visible)\n\t\treturn;\n\tif (glyph->Colored)\n\t\tcol |= ~IM_COL32_A_MASK;\n\tfloat scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;\n\tfloat x = IM_FLOOR(pos.x);\n\tfloat y = IM_FLOOR(pos.y);\n\tdraw_list->PrimReserve(6, 4);\n\tdraw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);\n}\n\n// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.\nvoid ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const\n{\n\tif (!text_end)\n\t\ttext_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.\n\n\t// Align to be pixel perfect\n\tfloat x = IM_FLOOR(pos.x);\n\tfloat y = IM_FLOOR(pos.y);\n\tif (y > clip_rect.w)\n\t\treturn;\n\n\tconst float start_x = x;\n\tconst float scale = size / FontSize;\n\tconst float line_height = FontSize * scale;\n\tconst bool word_wrap_enabled = (wrap_width > 0.0f);\n\n\t// Fast-forward to first visible line\n\tconst char* s = text_begin;\n\tif (y + line_height < clip_rect.y)\n\t\twhile (y + line_height < clip_rect.y && s < text_end)\n\t\t{\n\t\t\tconst char* line_end = (const char*)memchr(s, '\\n', text_end - s);\n\t\t\tif (word_wrap_enabled)\n\t\t\t{\n\t\t\t\t// FIXME-OPT: This is not optimal as do first do a search for \\n before calling CalcWordWrapPositionA().\n\t\t\t\t// If the specs for CalcWordWrapPositionA() were reworked to optionally return on \\n we could combine both.\n\t\t\t\t// However it is still better than nothing performing the fast-forward!\n\t\t\t\ts = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width);\n\t\t\t\ts = CalcWordWrapNextLineStartA(s, text_end);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts = line_end ? line_end + 1 : text_end;\n\t\t\t}\n\t\t\ty += line_height;\n\t\t}\n\n\t// For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()\n\t// Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm)\n\tif (text_end - s > 10000 && !word_wrap_enabled)\n\t{\n\t\tconst char* s_end = s;\n\t\tfloat y_end = y;\n\t\twhile (y_end < clip_rect.w && s_end < text_end)\n\t\t{\n\t\t\ts_end = (const char*)memchr(s_end, '\\n', text_end - s_end);\n\t\t\ts_end = s_end ? s_end + 1 : text_end;\n\t\t\ty_end += line_height;\n\t\t}\n\t\ttext_end = s_end;\n\t}\n\tif (s == text_end)\n\t\treturn;\n\n\t// Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)\n\tconst int vtx_count_max = (int)(text_end - s) * 4;\n\tconst int idx_count_max = (int)(text_end - s) * 6;\n\tconst int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;\n\tdraw_list->PrimReserve(idx_count_max, vtx_count_max);\n\tImDrawVert* vtx_write = draw_list->_VtxWritePtr;\n\tImDrawIdx* idx_write = draw_list->_IdxWritePtr;\n\tunsigned int vtx_index = draw_list->_VtxCurrentIdx;\n\n\tconst ImU32 col_untinted = col | ~IM_COL32_A_MASK;\n\tconst char* word_wrap_eol = NULL;\n\n\twhile (s < text_end)\n\t{\n\t\tif (word_wrap_enabled)\n\t\t{\n\t\t\t// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.\n\t\t\tif (!word_wrap_eol)\n\t\t\t\tword_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x));\n\n\t\t\tif (s >= word_wrap_eol)\n\t\t\t{\n\t\t\t\tx = start_x;\n\t\t\t\ty += line_height;\n\t\t\t\tword_wrap_eol = NULL;\n\t\t\t\ts = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Decode and advance source\n\t\tunsigned int c = (unsigned int)*s;\n\t\tif (c < 0x80)\n\t\t\ts += 1;\n\t\telse\n\t\t\ts += ImTextCharFromUtf8(&c, s, text_end);\n\n\t\tif (c < 32)\n\t\t{\n\t\t\tif (c == '\\n')\n\t\t\t{\n\t\t\t\tx = start_x;\n\t\t\t\ty += line_height;\n\t\t\t\tif (y > clip_rect.w)\n\t\t\t\t\tbreak; // break out of main loop\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c == '\\r')\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tconst ImFontGlyph* glyph = FindGlyph((ImWchar)c);\n\t\tif (glyph == NULL)\n\t\t\tcontinue;\n\n\t\tfloat char_width = glyph->AdvanceX * scale;\n\t\tif (glyph->Visible)\n\t\t{\n\t\t\t// We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w\n\t\t\tfloat x1 = x + glyph->X0 * scale;\n\t\t\tfloat x2 = x + glyph->X1 * scale;\n\t\t\tfloat y1 = y + glyph->Y0 * scale;\n\t\t\tfloat y2 = y + glyph->Y1 * scale;\n\t\t\tif (x1 <= clip_rect.z && x2 >= clip_rect.x)\n\t\t\t{\n\t\t\t\t// Render a character\n\t\t\t\tfloat u1 = glyph->U0;\n\t\t\t\tfloat v1 = glyph->V0;\n\t\t\t\tfloat u2 = glyph->U1;\n\t\t\t\tfloat v2 = glyph->V1;\n\n\t\t\t\t// CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.\n\t\t\t\tif (cpu_fine_clip)\n\t\t\t\t{\n\t\t\t\t\tif (x1 < clip_rect.x)\n\t\t\t\t\t{\n\t\t\t\t\t\tu1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);\n\t\t\t\t\t\tx1 = clip_rect.x;\n\t\t\t\t\t}\n\t\t\t\t\tif (y1 < clip_rect.y)\n\t\t\t\t\t{\n\t\t\t\t\t\tv1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);\n\t\t\t\t\t\ty1 = clip_rect.y;\n\t\t\t\t\t}\n\t\t\t\t\tif (x2 > clip_rect.z)\n\t\t\t\t\t{\n\t\t\t\t\t\tu2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);\n\t\t\t\t\t\tx2 = clip_rect.z;\n\t\t\t\t\t}\n\t\t\t\t\tif (y2 > clip_rect.w)\n\t\t\t\t\t{\n\t\t\t\t\t\tv2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);\n\t\t\t\t\t\ty2 = clip_rect.w;\n\t\t\t\t\t}\n\t\t\t\t\tif (y1 >= y2)\n\t\t\t\t\t{\n\t\t\t\t\t\tx += char_width;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support for untinted glyphs\n\t\t\t\tImU32 glyph_col = glyph->Colored ? col_untinted : col;\n\n\t\t\t\t// We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:\n\t\t\t\t{\n\t\t\t\t\tvtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;\n\t\t\t\t\tvtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;\n\t\t\t\t\tvtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;\n\t\t\t\t\tvtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;\n\t\t\t\t\tidx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);\n\t\t\t\t\tidx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);\n\t\t\t\t\tvtx_write += 4;\n\t\t\t\t\tvtx_index += 4;\n\t\t\t\t\tidx_write += 6;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tx += char_width;\n\t}\n\n\t// Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.\n\tdraw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()\n\tdraw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);\n\tdraw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);\n\tdraw_list->_VtxWritePtr = vtx_write;\n\tdraw_list->_IdxWritePtr = idx_write;\n\tdraw_list->_VtxCurrentIdx = vtx_index;\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGui Internal Render Helpers\n//-----------------------------------------------------------------------------\n// Vaguely redesigned to stop accessing ImGui global state:\n// - RenderArrow()\n// - RenderBullet()\n// - RenderCheckMark()\n// - RenderArrowPointingAt()\n// - RenderRectFilledRangeH()\n// - RenderRectFilledWithHole()\n//-----------------------------------------------------------------------------\n// Function in need of a redesign (legacy mess)\n// - RenderColorRectWithAlphaCheckerboard()\n//-----------------------------------------------------------------------------\n\n// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state\nvoid ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)\n{\n\tconst float h = draw_list->_Data->FontSize * 1.00f;\n\tfloat r = h * 0.40f * scale;\n\tImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);\n\n\tImVec2 a, b, c;\n\tswitch (dir)\n\t{\n\tcase ImGuiDir_Up:\n\tcase ImGuiDir_Down:\n\t\tif (dir == ImGuiDir_Up) r = -r;\n\t\ta = ImVec2(+0.000f, +0.750f) * r;\n\t\tb = ImVec2(-0.866f, -0.750f) * r;\n\t\tc = ImVec2(+0.866f, -0.750f) * r;\n\t\tbreak;\n\tcase ImGuiDir_Left:\n\tcase ImGuiDir_Right:\n\t\tif (dir == ImGuiDir_Left) r = -r;\n\t\ta = ImVec2(+0.750f, +0.000f) * r;\n\t\tb = ImVec2(-0.750f, +0.866f) * r;\n\t\tc = ImVec2(-0.750f, -0.866f) * r;\n\t\tbreak;\n\tcase ImGuiDir_None:\n\tcase ImGuiDir_COUNT:\n\t\tIM_ASSERT(0);\n\t\tbreak;\n\t}\n\tdraw_list->AddTriangleFilled(center + a, center + b, center + c, col);\n}\n\nvoid ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)\n{\n\t// FIXME-OPT: This should be baked in font.\n\tdraw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);\n}\n\nvoid ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)\n{\n\tfloat thickness = ImMax(sz / 5.0f, 1.0f);\n\tsz -= thickness * 0.5f;\n\tpos += ImVec2(thickness * 0.25f, thickness * 0.25f);\n\n\tfloat third = sz / 3.0f;\n\tfloat bx = pos.x + third;\n\tfloat by = pos.y + sz - third * 0.5f;\n\tdraw_list->PathLineTo(ImVec2(bx - third, by - third));\n\tdraw_list->PathLineTo(ImVec2(bx, by));\n\tdraw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));\n\tdraw_list->PathStroke(col, 0, thickness);\n}\n\n// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.\nvoid ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)\n{\n\tswitch (direction)\n\t{\n\tcase ImGuiDir_Left:  draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return;\n\tcase ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;\n\tcase ImGuiDir_Up:    draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;\n\tcase ImGuiDir_Down:  draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;\n\tcase ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings\n\t}\n}\n\nstatic inline float ImAcos01(float x)\n{\n\tif (x <= 0.0f) return IM_PI * 0.5f;\n\tif (x >= 1.0f) return 0.0f;\n\treturn ImAcos(x);\n\t//return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.\n}\n\n// FIXME: Cleanup and move code to ImDrawList.\nvoid ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)\n{\n\tif (x_end_norm == x_start_norm)\n\t\treturn;\n\tif (x_start_norm > x_end_norm)\n\t\tImSwap(x_start_norm, x_end_norm);\n\n\tImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);\n\tImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);\n\tif (rounding == 0.0f)\n\t{\n\t\tdraw_list->AddRectFilled(p0, p1, col, 0.0f);\n\t\treturn;\n\t}\n\n\trounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);\n\tconst float inv_rounding = 1.0f / rounding;\n\tconst float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);\n\tconst float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);\n\tconst float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.\n\tconst float x0 = ImMax(p0.x, rect.Min.x + rounding);\n\tif (arc0_b == arc0_e)\n\t{\n\t\tdraw_list->PathLineTo(ImVec2(x0, p1.y));\n\t\tdraw_list->PathLineTo(ImVec2(x0, p0.y));\n\t}\n\telse if (arc0_b == 0.0f && arc0_e == half_pi)\n\t{\n\t\tdraw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL\n\t\tdraw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR\n\t}\n\telse\n\t{\n\t\tdraw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL\n\t\tdraw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR\n\t}\n\tif (p1.x > rect.Min.x + rounding)\n\t{\n\t\tconst float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);\n\t\tconst float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);\n\t\tconst float x1 = ImMin(p1.x, rect.Max.x - rounding);\n\t\tif (arc1_b == arc1_e)\n\t\t{\n\t\t\tdraw_list->PathLineTo(ImVec2(x1, p0.y));\n\t\t\tdraw_list->PathLineTo(ImVec2(x1, p1.y));\n\t\t}\n\t\telse if (arc1_b == 0.0f && arc1_e == half_pi)\n\t\t{\n\t\t\tdraw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR\n\t\t\tdraw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdraw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR\n\t\t\tdraw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR\n\t\t}\n\t}\n\tdraw_list->PathFillConvex(col);\n}\n\nvoid ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding)\n{\n\tconst bool fill_L = (inner.Min.x > outer.Min.x);\n\tconst bool fill_R = (inner.Max.x < outer.Max.x);\n\tconst bool fill_U = (inner.Min.y > outer.Min.y);\n\tconst bool fill_D = (inner.Max.y < outer.Max.y);\n\tif (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));\n\tif (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));\n\tif (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));\n\tif (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));\n\tif (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);\n\tif (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);\n\tif (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);\n\tif (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight);\n}\n\n// Helper for ColorPicker4()\n// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.\n// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether.\n// FIXME: uses ImGui::GetColorU32\nvoid ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags)\n{\n\tif ((flags & ImDrawFlags_RoundCornersMask_) == 0)\n\t\tflags = ImDrawFlags_RoundCornersDefault_;\n\tif (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)\n\t{\n\t\tImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));\n\t\tImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));\n\t\tdraw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);\n\n\t\tint yi = 0;\n\t\tfor (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)\n\t\t{\n\t\t\tfloat y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);\n\t\t\tif (y2 <= y1)\n\t\t\t\tcontinue;\n\t\t\tfor (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)\n\t\t\t{\n\t\t\t\tfloat x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);\n\t\t\t\tif (x2 <= x1)\n\t\t\t\t\tcontinue;\n\t\t\t\tImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;\n\t\t\t\tif (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; }\n\t\t\t\tif (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; }\n\n\t\t\t\t// Combine flags\n\t\t\t\tcell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags);\n\t\t\t\tdraw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tdraw_list->AddRectFilled(p_min, p_max, col, rounding, flags);\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] Decompression code\n//-----------------------------------------------------------------------------\n// Compressed with stb_compress() then converted to a C array and encoded as base85.\n// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.\n// The purpose of encoding as base85 instead of \"0x00,0x01,...\" style is only save on _source code_ size.\n// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h\n//-----------------------------------------------------------------------------\n\nstatic unsigned int stb_decompress_length(const unsigned char* input)\n{\n\treturn (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];\n}\n\nstatic unsigned char* stb__barrier_out_e, * stb__barrier_out_b;\nstatic const unsigned char* stb__barrier_in_b;\nstatic unsigned char* stb__dout;\nstatic void stb__match(const unsigned char* data, unsigned int length)\n{\n\t// INVERSE of memmove... write each byte before copying the next...\n\tIM_ASSERT(stb__dout + length <= stb__barrier_out_e);\n\tif (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }\n\tif (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e + 1; return; }\n\twhile (length--) *stb__dout++ = *data++;\n}\n\nstatic void stb__lit(const unsigned char* data, unsigned int length)\n{\n\tIM_ASSERT(stb__dout + length <= stb__barrier_out_e);\n\tif (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }\n\tif (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e + 1; return; }\n\tmemcpy(stb__dout, data, length);\n\tstb__dout += length;\n}\n\n#define stb__in2(x)   ((i[x] << 8) + i[(x)+1])\n#define stb__in3(x)   ((i[x] << 16) + stb__in2((x)+1))\n#define stb__in4(x)   ((i[x] << 24) + stb__in3((x)+1))\n\nstatic const unsigned char* stb_decompress_token(const unsigned char* i)\n{\n\tif (*i >= 0x20) { // use fewer if's for cases that expand small\n\t\tif (*i >= 0x80)       stb__match(stb__dout - i[1] - 1, i[0] - 0x80 + 1), i += 2;\n\t\telse if (*i >= 0x40)  stb__match(stb__dout - (stb__in2(0) - 0x4000 + 1), i[2] + 1), i += 3;\n\t\telse /* *i >= 0x20 */ stb__lit(i + 1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);\n\t}\n\telse { // more ifs for cases that expand large, since overhead is amortized\n\t\tif (*i >= 0x18)       stb__match(stb__dout - (stb__in3(0) - 0x180000 + 1), i[3] + 1), i += 4;\n\t\telse if (*i >= 0x10)  stb__match(stb__dout - (stb__in3(0) - 0x100000 + 1), stb__in2(3) + 1), i += 5;\n\t\telse if (*i >= 0x08)  stb__lit(i + 2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);\n\t\telse if (*i == 0x07)  stb__lit(i + 3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);\n\t\telse if (*i == 0x06)  stb__match(stb__dout - (stb__in3(1) + 1), i[4] + 1), i += 5;\n\t\telse if (*i == 0x04)  stb__match(stb__dout - (stb__in3(1) + 1), stb__in2(4) + 1), i += 6;\n\t}\n\treturn i;\n}\n\nstatic unsigned int stb_adler32(unsigned int adler32, unsigned char* buffer, unsigned int buflen)\n{\n\tconst unsigned long ADLER_MOD = 65521;\n\tunsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;\n\tunsigned long blocklen = buflen % 5552;\n\n\tunsigned long i;\n\twhile (buflen) {\n\t\tfor (i = 0; i + 7 < blocklen; i += 8) {\n\t\t\ts1 += buffer[0], s2 += s1;\n\t\t\ts1 += buffer[1], s2 += s1;\n\t\t\ts1 += buffer[2], s2 += s1;\n\t\t\ts1 += buffer[3], s2 += s1;\n\t\t\ts1 += buffer[4], s2 += s1;\n\t\t\ts1 += buffer[5], s2 += s1;\n\t\t\ts1 += buffer[6], s2 += s1;\n\t\t\ts1 += buffer[7], s2 += s1;\n\n\t\t\tbuffer += 8;\n\t\t}\n\n\t\tfor (; i < blocklen; ++i)\n\t\t\ts1 += *buffer++, s2 += s1;\n\n\t\ts1 %= ADLER_MOD, s2 %= ADLER_MOD;\n\t\tbuflen -= blocklen;\n\t\tblocklen = 5552;\n\t}\n\treturn (unsigned int)(s2 << 16) + (unsigned int)s1;\n}\n\nstatic unsigned int stb_decompress(unsigned char* output, const unsigned char* i, unsigned int /*length*/)\n{\n\tif (stb__in4(0) != 0x57bC0000) return 0;\n\tif (stb__in4(4) != 0)          return 0; // error! stream is > 4GB\n\tconst unsigned int olen = stb_decompress_length(i);\n\tstb__barrier_in_b = i;\n\tstb__barrier_out_e = output + olen;\n\tstb__barrier_out_b = output;\n\ti += 16;\n\n\tstb__dout = output;\n\tfor (;;) {\n\t\tconst unsigned char* old_i = i;\n\t\ti = stb_decompress_token(i);\n\t\tif (i == old_i) {\n\t\t\tif (*i == 0x05 && i[1] == 0xfa) {\n\t\t\t\tIM_ASSERT(stb__dout == output + olen);\n\t\t\t\tif (stb__dout != output + olen) return 0;\n\t\t\t\tif (stb_adler32(1, output, olen) != (unsigned int)stb__in4(2))\n\t\t\t\t\treturn 0;\n\t\t\t\treturn olen;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tIM_ASSERT(0); /* NOTREACHED */\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tIM_ASSERT(stb__dout <= output + olen);\n\t\tif (stb__dout > output + olen)\n\t\t\treturn 0;\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] Default font data (ProggyClean.ttf)\n//-----------------------------------------------------------------------------\n// ProggyClean.ttf\n// Copyright (c) 2004, 2005 Tristan Grimmer\n// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)\n// Download and more information at http://upperbounds.net\n//-----------------------------------------------------------------------------\n// File: 'ProggyClean.ttf' (41208 bytes)\n// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding).\n// The purpose of encoding as base85 instead of \"0x00,0x01,...\" style is only save on _source code_ size.\n//-----------------------------------------------------------------------------\nstatic const char proggy_clean_ttf_compressed_data_base85[11980 + 1] =\n\"7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/\"\n\"2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#\"\n\"`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL\"\n\"i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N\"\n\"kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N\"\n\"*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)\"\n\"tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX\"\n\"ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc.\"\n\"x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G\"\n\"CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)\"\n\"U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#\"\n\"'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM\"\n\"_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu\"\n\"Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/\"\n\"/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L\"\n\"%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#\"\n\"OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)(\"\n\"h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h\"\n\"o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO\"\n\"j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-\"\n\"sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-\"\n\"eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO\"\n\"M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%\"\n\"LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]\"\n\"%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et\"\n\"Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:\"\n\"a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL(\"\n\"$/V,;(kXZejWO`<[5?\\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<\"\n\"nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?\"\n\"7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;\"\n\")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M\"\n\"D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(\"\n\"P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs\"\n\"bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q\"\n\"h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-\"\n\"V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i\"\n\"sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7\"\n\".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@\"\n\"$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*\"\n\"hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u\"\n\"@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#\"\n\"w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#\"\n\"u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0\"\n\"d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8\"\n\"6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#\"\n\"b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD\"\n\":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+\"\n\"tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*\"\n\"$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7\"\n\":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A\"\n\"7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7\"\n\"u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT\"\n\"LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M\"\n\":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>\"\n\"_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%\"\n\"hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;\"\n\"^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:\"\n\"+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%\"\n\"9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-\"\n\"CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*\"\n\"hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY\"\n\"8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-\"\n\"S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`\"\n\"0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/\"\n\"+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj\"\n\"M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V\"\n\"?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK\"\n\"Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa\"\n\">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>\"\n\"[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I\"\n\"wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#\"\n\"Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$\"\n\"MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)\"\n\"i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo\"\n\"1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P\"\n\"iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO\"\n\"URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#\"\n\";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>\"\n\"w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#\"\n\"d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4\"\n\"A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#\"\n\"/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#\"\n\"m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#\"\n\"TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP\"\n\"GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp\"\n\"O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#\";\n\nstatic const char* GetDefaultCompressedFontDataTTFBase85()\n{\n\treturn proggy_clean_ttf_compressed_data_base85;\n}\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imgui_freetype.cpp",
    "content": "// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)\n// (code)\n\n// Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype\n// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut.\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly.\n//  2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL.\n//  2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.\n//  2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a prefered texture format.\n//  2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).\n//  2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'.\n//              renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas().\n//  2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails.\n//  2019/02/09: added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!)\n//  2019/01/15: added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().\n//  2019/01/10: re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.\n//  2018/06/08: added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.\n//  2018/02/04: moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)\n//  2018/01/22: fix for addition of ImFontAtlas::TexUvscale member.\n//  2017/10/22: minor inconsequential change to match change in master (removed an unnecessary statement).\n//  2017/09/26: fixes for imgui internal changes.\n//  2017/08/26: cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.\n//  2017/08/16: imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.\n\n// About Gamma Correct Blending:\n// - FreeType assumes blending in linear space rather than gamma space.\n// - See https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph\n// - For correct results you need to be using sRGB and convert to linear space in the pixel shader output.\n// - The default dear imgui styles will be impacted by this change (alpha values will need tweaking).\n\n// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).\n\n#include \"imgui_freetype.h\"\n#include \"imgui_internal.h\"     // ImMin,ImMax,ImFontAtlasBuild*,\n#include <stdint.h>\n#include <ft2build.h>\n#include FT_FREETYPE_H          // <freetype/freetype.h>\n#include FT_MODULE_H            // <freetype/ftmodapi.h>\n#include FT_GLYPH_H             // <freetype/ftglyph.h>\n#include FT_SYNTHESIS_H         // <freetype/ftsynth.h>\n\n#ifdef _MSC_VER\n#pragma warning (push)\n#pragma warning (disable: 4505)     // unreferenced local function has been removed (stb stuff)\n#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n#endif\n\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wpragmas\"                  // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wunused-function\"          // warning: 'xxxx' defined but not used\n#pragma GCC diagnostic ignored \"-Wsubobject-linkage\"        // warning: 'xxxx' has a field 'xxxx' whose type uses the anonymous namespace\n#endif\n\n//-------------------------------------------------------------------------\n// Data\n//-------------------------------------------------------------------------\n\n// Default memory allocators\nstatic void* ImGuiFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }\nstatic void  ImGuiFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }\n\n// Current memory allocators\nstatic void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFreeTypeDefaultAllocFunc;\nstatic void  (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;\nstatic void* GImGuiFreeTypeAllocatorUserData = NULL;\n\n//-------------------------------------------------------------------------\n// Code\n//-------------------------------------------------------------------------\n\nnamespace\n{\n\t// Glyph metrics:\n\t// --------------\n\t//\n\t//                       xmin                     xmax\n\t//                        |                         |\n\t//                        |<-------- width -------->|\n\t//                        |                         |\n\t//              |         +-------------------------+----------------- ymax\n\t//              |         |    ggggggggg   ggggg    |     ^        ^\n\t//              |         |   g:::::::::ggg::::g    |     |        |\n\t//              |         |  g:::::::::::::::::g    |     |        |\n\t//              |         | g::::::ggggg::::::gg    |     |        |\n\t//              |         | g:::::g     g:::::g     |     |        |\n\t//    offsetX  -|-------->| g:::::g     g:::::g     |  offsetY     |\n\t//              |         | g:::::g     g:::::g     |     |        |\n\t//              |         | g::::::g    g:::::g     |     |        |\n\t//              |         | g:::::::ggggg:::::g     |     |        |\n\t//              |         |  g::::::::::::::::g     |     |      height\n\t//              |         |   gg::::::::::::::g     |     |        |\n\t//  baseline ---*---------|---- gggggggg::::::g-----*--------      |\n\t//            / |         |             g:::::g     |              |\n\t//     origin   |         | gggggg      g:::::g     |              |\n\t//              |         | g:::::gg   gg:::::g     |              |\n\t//              |         |  g::::::ggg:::::::g     |              |\n\t//              |         |   gg:::::::::::::g      |              |\n\t//              |         |     ggg::::::ggg        |              |\n\t//              |         |         gggggg          |              v\n\t//              |         +-------------------------+----------------- ymin\n\t//              |                                   |\n\t//              |------------- advanceX ----------->|\n\n\t// A structure that describe a glyph.\n\tstruct GlyphInfo\n\t{\n\t\tint         Width;              // Glyph's width in pixels.\n\t\tint         Height;             // Glyph's height in pixels.\n\t\tFT_Int      OffsetX;            // The distance from the origin (\"pen position\") to the left of the glyph.\n\t\tFT_Int      OffsetY;            // The distance from the origin to the top of the glyph. This is usually a value < 0.\n\t\tfloat       AdvanceX;           // The distance from the origin to the origin of the next glyph. This is usually a value > 0.\n\t\tbool        IsColored;          // The glyph is colored\n\t};\n\n\t// Font parameters and metrics.\n\tstruct FontInfo\n\t{\n\t\tuint32_t    PixelHeight;        // Size this font was generated with.\n\t\tfloat       Ascender;           // The pixel extents above the baseline in pixels (typically positive).\n\t\tfloat       Descender;          // The extents below the baseline in pixels (typically negative).\n\t\tfloat       LineSpacing;        // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.\n\t\tfloat       LineGap;            // The spacing in pixels between one row's descent and the next row's ascent.\n\t\tfloat       MaxAdvanceWidth;    // This field gives the maximum horizontal cursor advance for all glyphs in the font.\n\t};\n\n\t// FreeType glyph rasterizer.\n\t// NB: No ctor/dtor, explicitly call Init()/Shutdown()\n\tstruct FreeTypeFont\n\t{\n\t\tbool                    InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.\n\t\tvoid                    CloseFont();\n\t\tvoid                    SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size\n\t\tconst FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);\n\t\tconst FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);\n\t\tvoid                    BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);\n\t\t~FreeTypeFont() { CloseFont(); }\n\n\t\t// [Internals]\n\t\tFontInfo        Info;               // Font descriptor of the current font.\n\t\tFT_Face         Face;\n\t\tunsigned int    UserFlags;          // = ImFontConfig::RasterizerFlags\n\t\tFT_Int32        LoadFlags;\n\t\tFT_Render_Mode  RenderMode;\n\t};\n\n\t// From SDL_ttf: Handy routines for converting from fixed point\n#define FT_CEIL(X)  (((X + 63) & -64) / 64)\n\n\tbool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)\n\t{\n\t\tFT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);\n\t\tif (error != 0)\n\t\t\treturn false;\n\t\terror = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);\n\t\tif (error != 0)\n\t\t\treturn false;\n\n\t\t// Convert to FreeType flags (NB: Bold and Oblique are processed separately)\n\t\tUserFlags = cfg.FontBuilderFlags | extra_font_builder_flags;\n\n\t\tLoadFlags = 0;\n\t\tif ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)\n\t\t\tLoadFlags |= FT_LOAD_NO_BITMAP;\n\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting)\n\t\t\tLoadFlags |= FT_LOAD_NO_HINTING;\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint)\n\t\t\tLoadFlags |= FT_LOAD_NO_AUTOHINT;\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint)\n\t\t\tLoadFlags |= FT_LOAD_FORCE_AUTOHINT;\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting)\n\t\t\tLoadFlags |= FT_LOAD_TARGET_LIGHT;\n\t\telse if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting)\n\t\t\tLoadFlags |= FT_LOAD_TARGET_MONO;\n\t\telse\n\t\t\tLoadFlags |= FT_LOAD_TARGET_NORMAL;\n\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome)\n\t\t\tRenderMode = FT_RENDER_MODE_MONO;\n\t\telse\n\t\t\tRenderMode = FT_RENDER_MODE_NORMAL;\n\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)\n\t\t\tLoadFlags |= FT_LOAD_COLOR;\n\n\t\tmemset(&Info, 0, sizeof(Info));\n\t\tSetPixelHeight((uint32_t)cfg.SizePixels);\n\n\t\treturn true;\n\t}\n\n\tvoid FreeTypeFont::CloseFont()\n\t{\n\t\tif (Face)\n\t\t{\n\t\t\tFT_Done_Face(Face);\n\t\t\tFace = NULL;\n\t\t}\n\t}\n\n\tvoid FreeTypeFont::SetPixelHeight(int pixel_height)\n\t{\n\t\t// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'\n\t\t// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.\n\t\t// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.\n\t\tFT_Size_RequestRec req;\n\t\treq.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;\n\t\treq.width = 0;\n\t\treq.height = (uint32_t)pixel_height * 64;\n\t\treq.horiResolution = 0;\n\t\treq.vertResolution = 0;\n\t\tFT_Request_Size(Face, &req);\n\n\t\t// Update font info\n\t\tFT_Size_Metrics metrics = Face->size->metrics;\n\t\tInfo.PixelHeight = (uint32_t)pixel_height;\n\t\tInfo.Ascender = (float)FT_CEIL(metrics.ascender);\n\t\tInfo.Descender = (float)FT_CEIL(metrics.descender);\n\t\tInfo.LineSpacing = (float)FT_CEIL(metrics.height);\n\t\tInfo.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender);\n\t\tInfo.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);\n\t}\n\n\tconst FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)\n\t{\n\t\tuint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);\n\t\tif (glyph_index == 0)\n\t\t\treturn NULL;\n\n\t\t// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.\n\t\t// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076\n\t\t// - https://github.com/ocornut/imgui/issues/4567\n\t\t// - https://github.com/ocornut/imgui/issues/4566\n\t\t// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.\n\t\tFT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);\n\t\tif (error)\n\t\t\treturn NULL;\n\n\t\t// Need an outline for this to work\n\t\tFT_GlyphSlot slot = Face->glyph;\n\t\tIM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP);\n\n\t\t// Apply convenience transform (this is not picking from real \"Bold\"/\"Italic\" fonts! Merely applying FreeType helper transform. Oblique == Slanting)\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_Bold)\n\t\t\tFT_GlyphSlot_Embolden(slot);\n\t\tif (UserFlags & ImGuiFreeTypeBuilderFlags_Oblique)\n\t\t{\n\t\t\tFT_GlyphSlot_Oblique(slot);\n\t\t\t//FT_BBox bbox;\n\t\t\t//FT_Outline_Get_BBox(&slot->outline, &bbox);\n\t\t\t//slot->metrics.width = bbox.xMax - bbox.xMin;\n\t\t\t//slot->metrics.height = bbox.yMax - bbox.yMin;\n\t\t}\n\n\t\treturn &slot->metrics;\n\t}\n\n\tconst FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)\n\t{\n\t\tFT_GlyphSlot slot = Face->glyph;\n\t\tFT_Error error = FT_Render_Glyph(slot, RenderMode);\n\t\tif (error != 0)\n\t\t\treturn NULL;\n\n\t\tFT_Bitmap* ft_bitmap = &Face->glyph->bitmap;\n\t\tout_glyph_info->Width = (int)ft_bitmap->width;\n\t\tout_glyph_info->Height = (int)ft_bitmap->rows;\n\t\tout_glyph_info->OffsetX = Face->glyph->bitmap_left;\n\t\tout_glyph_info->OffsetY = -Face->glyph->bitmap_top;\n\t\tout_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);\n\t\tout_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);\n\n\t\treturn ft_bitmap;\n\t}\n\n\tvoid FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)\n\t{\n\t\tIM_ASSERT(ft_bitmap != NULL);\n\t\tconst uint32_t w = ft_bitmap->width;\n\t\tconst uint32_t h = ft_bitmap->rows;\n\t\tconst uint8_t* src = ft_bitmap->buffer;\n\t\tconst uint32_t src_pitch = ft_bitmap->pitch;\n\n\t\tswitch (ft_bitmap->pixel_mode)\n\t\t{\n\t\tcase FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.\n\t\t{\n\t\t\tif (multiply_table == NULL)\n\t\t\t{\n\t\t\t\tfor (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)\n\t\t\t\t\tfor (uint32_t x = 0; x < w; x++)\n\t\t\t\t\t\tdst[x] = IM_COL32(255, 255, 255, src[x]);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)\n\t\t\t\t\tfor (uint32_t x = 0; x < w; x++)\n\t\t\t\t\t\tdst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.\n\t\t{\n\t\t\tuint8_t color0 = multiply_table ? multiply_table[0] : 0;\n\t\t\tuint8_t color1 = multiply_table ? multiply_table[255] : 255;\n\t\t\tfor (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)\n\t\t\t{\n\t\t\t\tuint8_t bits = 0;\n\t\t\t\tconst uint8_t* bits_ptr = src;\n\t\t\t\tfor (uint32_t x = 0; x < w; x++, bits <<= 1)\n\t\t\t\t{\n\t\t\t\t\tif ((x & 7) == 0)\n\t\t\t\t\t\tbits = *bits_ptr++;\n\t\t\t\t\tdst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase FT_PIXEL_MODE_BGRA:\n\t\t{\n\t\t\t// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.\n#define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f)\n\t\t\tif (multiply_table == NULL)\n\t\t\t{\n\t\t\t\tfor (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)\n\t\t\t\t\tfor (uint32_t x = 0; x < w; x++)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];\n\t\t\t\t\t\tdst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);\n\t\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32_t x = 0; x < w; x++)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];\n\t\t\t\t\t\tdst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n#undef DE_MULTIPLY\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tIM_ASSERT(0 && \"FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!\");\n\t\t}\n\t}\n} // namespace\n\n#ifndef STB_RECT_PACK_IMPLEMENTATION                        // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)\n#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION\n#define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)\n#define STBRP_STATIC\n#define STB_RECT_PACK_IMPLEMENTATION\n#endif\n#ifdef IMGUI_STB_RECT_PACK_FILENAME\n#include IMGUI_STB_RECT_PACK_FILENAME\n#else\n#include \"imstb_rectpack.h\"\n#endif\n#endif\n\nstruct ImFontBuildSrcGlyphFT\n{\n\tGlyphInfo           Info;\n\tuint32_t            Codepoint;\n\tunsigned int* BitmapData;         // Point within one of the dst_tmp_bitmap_buffers[] array\n\n\tImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); }\n};\n\nstruct ImFontBuildSrcDataFT\n{\n\tFreeTypeFont        Font;\n\tstbrp_rect* Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.\n\tconst ImWchar* SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)\n\tint                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]\n\tint                 GlyphsHighest;      // Highest requested codepoint\n\tint                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)\n\tImBitVector         GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)\n\tImVector<ImFontBuildSrcGlyphFT>   GlyphsList;\n};\n\n// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)\nstruct ImFontBuildDstDataFT\n{\n\tint                 SrcCount;           // Number of source fonts targeting this destination font.\n\tint                 GlyphsHighest;\n\tint                 GlyphsCount;\n\tImBitVector         GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.\n};\n\nbool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)\n{\n\tIM_ASSERT(atlas->ConfigData.Size > 0);\n\n\tImFontAtlasBuildInit(atlas);\n\n\t// Clear atlas\n\tatlas->TexID = (ImTextureID)NULL;\n\tatlas->TexWidth = atlas->TexHeight = 0;\n\tatlas->TexUvScale = ImVec2(0.0f, 0.0f);\n\tatlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);\n\tatlas->ClearTexData();\n\n\t// Temporary storage for building\n\tbool src_load_color = false;\n\tImVector<ImFontBuildSrcDataFT> src_tmp_array;\n\tImVector<ImFontBuildDstDataFT> dst_tmp_array;\n\tsrc_tmp_array.resize(atlas->ConfigData.Size);\n\tdst_tmp_array.resize(atlas->Fonts.Size);\n\tmemset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());\n\tmemset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());\n\n\t// 1. Initialize font loading structure, check font data validity\n\tfor (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tFreeTypeFont& font_face = src_tmp.Font;\n\t\tIM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));\n\n\t\t// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)\n\t\tsrc_tmp.DstIndex = -1;\n\t\tfor (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)\n\t\t\tif (cfg.DstFont == atlas->Fonts[output_i])\n\t\t\t\tsrc_tmp.DstIndex = output_i;\n\t\tIM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?\n\t\tif (src_tmp.DstIndex == -1)\n\t\t\treturn false;\n\n\t\t// Load font\n\t\tif (!font_face.InitFont(ft_library, cfg, extra_flags))\n\t\t\treturn false;\n\n\t\t// Measure highest codepoints\n\t\tsrc_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;\n\t\tImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];\n\t\tsrc_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();\n\t\tfor (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)\n\t\t{\n\t\t\t// Check for valid range. This may also help detect *some* dangling pointers, because a common\n\t\t\t// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.\n\t\t\tIM_ASSERT(src_range[0] <= src_range[1]);\n\t\t\tsrc_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);\n\t\t}\n\t\tdst_tmp.SrcCount++;\n\t\tdst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);\n\t}\n\n\t// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.\n\tint total_glyphs_count = 0;\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];\n\t\tsrc_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);\n\t\tif (dst_tmp.GlyphsSet.Storage.empty())\n\t\t\tdst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);\n\n\t\tfor (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)\n\t\t\tfor (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++)\n\t\t\t{\n\t\t\t\tif (dst_tmp.GlyphsSet.TestBit(codepoint))    // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)\n\t\t\t\t\tcontinue;\n\t\t\t\tuint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)\n\t\t\t\tif (glyph_index == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Add to avail set/counters\n\t\t\t\tsrc_tmp.GlyphsCount++;\n\t\t\t\tdst_tmp.GlyphsCount++;\n\t\t\t\tsrc_tmp.GlyphsSet.SetBit(codepoint);\n\t\t\t\tdst_tmp.GlyphsSet.SetBit(codepoint);\n\t\t\t\ttotal_glyphs_count++;\n\t\t\t}\n\t}\n\n\t// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tsrc_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);\n\n\t\tIM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32));\n\t\tconst ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin();\n\t\tconst ImU32* it_end = src_tmp.GlyphsSet.Storage.end();\n\t\tfor (const ImU32* it = it_begin; it < it_end; it++)\n\t\t\tif (ImU32 entries_32 = *it)\n\t\t\t\tfor (ImU32 bit_n = 0; bit_n < 32; bit_n++)\n\t\t\t\t\tif (entries_32 & ((ImU32)1 << bit_n))\n\t\t\t\t\t{\n\t\t\t\t\t\tImFontBuildSrcGlyphFT src_glyph;\n\t\t\t\t\t\tsrc_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);\n\t\t\t\t\t\t//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..\n\t\t\t\t\t\tsrc_tmp.GlyphsList.push_back(src_glyph);\n\t\t\t\t\t}\n\t\tsrc_tmp.GlyphsSet.Clear();\n\t\tIM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);\n\t}\n\tfor (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)\n\t\tdst_tmp_array[dst_i].GlyphsSet.Clear();\n\tdst_tmp_array.clear();\n\n\t// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)\n\t// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)\n\tImVector<stbrp_rect> buf_rects;\n\tbuf_rects.resize(total_glyphs_count);\n\tmemset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());\n\n\t// Allocate temporary rasterization data buffers.\n\t// We could not find a way to retrieve accurate glyph size without rendering them.\n\t// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)\n\t// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations.\n\tconst int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;\n\tint buf_bitmap_current_used_bytes = 0;\n\tImVector<unsigned char*> buf_bitmap_buffers;\n\tbuf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));\n\n\t// 4. Gather glyphs sizes so we can pack them in our virtual canvas.\n\t// 8. Render/rasterize font characters into the texture\n\tint total_surface = 0;\n\tint buf_rects_out_n = 0;\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\tsrc_tmp.Rects = &buf_rects[buf_rects_out_n];\n\t\tbuf_rects_out_n += src_tmp.GlyphsCount;\n\n\t\t// Compute multiply table if requested\n\t\tconst bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);\n\t\tunsigned char multiply_table[256];\n\t\tif (multiply_enabled)\n\t\t\tImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);\n\n\t\t// Gather the sizes of all rectangles we will need to pack\n\t\tconst int padding = atlas->TexGlyphPadding;\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)\n\t\t{\n\t\t\tImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];\n\n\t\t\tconst FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);\n\t\t\tif (metrics == NULL)\n\t\t\t\tcontinue;\n\n\t\t\t// Render glyph into a bitmap (currently held by FreeType)\n\t\t\tconst FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);\n\t\t\tif (ft_bitmap == NULL)\n\t\t\t\tcontinue;\n\n\t\t\t// Allocate new temporary chunk if needed\n\t\t\tconst int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;\n\t\t\tif (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)\n\t\t\t{\n\t\t\t\tbuf_bitmap_current_used_bytes = 0;\n\t\t\t\tbuf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));\n\t\t\t}\n\t\t\tIM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead.\n\n\t\t\t// Blit rasterized pixels to our temporary buffer and keep a pointer to it.\n\t\t\tsrc_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes);\n\t\t\tbuf_bitmap_current_used_bytes += bitmap_size_in_bytes;\n\t\t\tsrc_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : NULL);\n\n\t\t\tsrc_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);\n\t\t\tsrc_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);\n\t\t\ttotal_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;\n\t\t}\n\t}\n\n\t// We need a width for the skyline algorithm, any width!\n\t// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.\n\t// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.\n\tconst int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;\n\tatlas->TexHeight = 0;\n\tif (atlas->TexDesiredWidth > 0)\n\t\tatlas->TexWidth = atlas->TexDesiredWidth;\n\telse\n\t\tatlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;\n\n\t// 5. Start packing\n\t// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).\n\tconst int TEX_HEIGHT_MAX = 1024 * 32;\n\tconst int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;\n\tImVector<stbrp_node> pack_nodes;\n\tpack_nodes.resize(num_nodes_for_packing_algorithm);\n\tstbrp_context pack_context;\n\tstbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size);\n\tImFontAtlasBuildPackCustomRects(atlas, &pack_context);\n\n\t// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\tstbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);\n\n\t\t// Extend texture height and mark missing glyphs as non-packed so we won't render them.\n\t\t// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)\n\t\t\tif (src_tmp.Rects[glyph_i].was_packed)\n\t\t\t\tatlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);\n\t}\n\n\t// 7. Allocate texture\n\tatlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);\n\tatlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);\n\tif (src_load_color)\n\t{\n\t\tsize_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;\n\t\tatlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);\n\t\tmemset(atlas->TexPixelsRGBA32, 0, tex_size);\n\t}\n\telse\n\t{\n\t\tsize_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;\n\t\tatlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);\n\t\tmemset(atlas->TexPixelsAlpha8, 0, tex_size);\n\t}\n\n\t// 8. Copy rasterized font characters back into the main texture\n\t// 9. Setup ImFont and glyphs for runtime\n\tbool tex_use_colors = false;\n\tfor (int src_i = 0; src_i < src_tmp_array.Size; src_i++)\n\t{\n\t\tImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];\n\t\tif (src_tmp.GlyphsCount == 0)\n\t\t\tcontinue;\n\n\t\t// When merging fonts with MergeMode=true:\n\t\t// - We can have multiple input fonts writing into a same destination font.\n\t\t// - dst_font->ConfigData is != from cfg which is our source configuration.\n\t\tImFontConfig& cfg = atlas->ConfigData[src_i];\n\t\tImFont* dst_font = cfg.DstFont;\n\n\t\tconst float ascent = src_tmp.Font.Info.Ascender;\n\t\tconst float descent = src_tmp.Font.Info.Descender;\n\t\tImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);\n\t\tconst float font_off_x = cfg.GlyphOffset.x;\n\t\tconst float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);\n\n\t\tconst int padding = atlas->TexGlyphPadding;\n\t\tfor (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)\n\t\t{\n\t\t\tImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];\n\t\t\tstbrp_rect& pack_rect = src_tmp.Rects[glyph_i];\n\t\t\tIM_ASSERT(pack_rect.was_packed);\n\t\t\tif (pack_rect.w == 0 && pack_rect.h == 0)\n\t\t\t\tcontinue;\n\n\t\t\tGlyphInfo& info = src_glyph.Info;\n\t\t\tIM_ASSERT(info.Width + padding <= pack_rect.w);\n\t\t\tIM_ASSERT(info.Height + padding <= pack_rect.h);\n\t\t\tconst int tx = pack_rect.x + padding;\n\t\t\tconst int ty = pack_rect.y + padding;\n\n\t\t\t// Register glyph\n\t\t\tfloat x0 = info.OffsetX + font_off_x;\n\t\t\tfloat y0 = info.OffsetY + font_off_y;\n\t\t\tfloat x1 = x0 + info.Width;\n\t\t\tfloat y1 = y0 + info.Height;\n\t\t\tfloat u0 = (tx) / (float)atlas->TexWidth;\n\t\t\tfloat v0 = (ty) / (float)atlas->TexHeight;\n\t\t\tfloat u1 = (tx + info.Width) / (float)atlas->TexWidth;\n\t\t\tfloat v1 = (ty + info.Height) / (float)atlas->TexHeight;\n\t\t\tdst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX);\n\n\t\t\tImFontGlyph* dst_glyph = &dst_font->Glyphs.back();\n\t\t\tIM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);\n\t\t\tif (src_glyph.Info.IsColored)\n\t\t\t\tdst_glyph->Colored = tex_use_colors = true;\n\n\t\t\t// Blit from temporary buffer to final texture\n\t\t\tsize_t blit_src_stride = (size_t)src_glyph.Info.Width;\n\t\t\tsize_t blit_dst_stride = (size_t)atlas->TexWidth;\n\t\t\tunsigned int* blit_src = src_glyph.BitmapData;\n\t\t\tif (atlas->TexPixelsAlpha8 != NULL)\n\t\t\t{\n\t\t\t\tunsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;\n\t\t\t\tfor (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)\n\t\t\t\t\tfor (int x = 0; x < info.Width; x++)\n\t\t\t\t\t\tblit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tunsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx;\n\t\t\t\tfor (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)\n\t\t\t\t\tfor (int x = 0; x < info.Width; x++)\n\t\t\t\t\t\tblit_dst[x] = blit_src[x];\n\t\t\t}\n\t\t}\n\n\t\tsrc_tmp.Rects = NULL;\n\t}\n\tatlas->TexPixelsUseColors = tex_use_colors;\n\n\t// Cleanup\n\tfor (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)\n\t\tIM_FREE(buf_bitmap_buffers[buf_i]);\n\tsrc_tmp_array.clear_destruct();\n\n\tImFontAtlasBuildFinish(atlas);\n\n\treturn true;\n}\n\n// FreeType memory allocation callbacks\nstatic void* FreeType_Alloc(FT_Memory /*memory*/, long size)\n{\n\treturn GImGuiFreeTypeAllocFunc((size_t)size, GImGuiFreeTypeAllocatorUserData);\n}\n\nstatic void FreeType_Free(FT_Memory /*memory*/, void* block)\n{\n\tGImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);\n}\n\nstatic void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)\n{\n\t// Implement realloc() as we don't ask user to provide it.\n\tif (block == NULL)\n\t\treturn GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);\n\n\tif (new_size == 0)\n\t{\n\t\tGImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);\n\t\treturn NULL;\n\t}\n\n\tif (new_size > cur_size)\n\t{\n\t\tvoid* new_block = GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);\n\t\tmemcpy(new_block, block, (size_t)cur_size);\n\t\tGImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);\n\t\treturn new_block;\n\t}\n\n\treturn block;\n}\n\nstatic bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas)\n{\n\t// FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html\n\tFT_MemoryRec_ memory_rec = {};\n\tmemory_rec.user = NULL;\n\tmemory_rec.alloc = &FreeType_Alloc;\n\tmemory_rec.free = &FreeType_Free;\n\tmemory_rec.realloc = &FreeType_Realloc;\n\n\t// https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library\n\tFT_Library ft_library;\n\tFT_Error error = FT_New_Library(&memory_rec, &ft_library);\n\tif (error != 0)\n\t\treturn false;\n\n\t// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.\n\tFT_Add_Default_Modules(ft_library);\n\n\tbool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags);\n\tFT_Done_Library(ft_library);\n\n\treturn ret;\n}\n\nconst ImFontBuilderIO* ImGuiFreeType::GetBuilderForFreeType()\n{\n\tstatic ImFontBuilderIO io;\n\tio.FontBuilder_Build = ImFontAtlasBuildWithFreeType;\n\treturn &io;\n}\n\nvoid ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)\n{\n\tGImGuiFreeTypeAllocFunc = alloc_func;\n\tGImGuiFreeTypeFreeFunc = free_func;\n\tGImGuiFreeTypeAllocatorUserData = user_data;\n}\n\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n\n#ifdef _MSC_VER\n#pragma warning (pop)\n#endif"
  },
  {
    "path": "KBotExt/imgui/imgui_freetype.h",
    "content": "// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)\n// (headers)\n\n#pragma once\n\n#include \"imgui.h\"      // IMGUI_API\n\n// Forward declarations\nstruct ImFontAtlas;\nstruct ImFontBuilderIO;\n\n// Hinting greatly impacts visuals (and glyph sizes).\n// - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.\n// - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h\n// - The Default hinting mode usually looks good, but may distort glyphs in an unusual way.\n// - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.\n// You can set those flags globaly in ImFontAtlas::FontBuilderFlags\n// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags\nenum ImGuiFreeTypeBuilderFlags\n{\n\tImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0,   // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.\n\tImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1,   // Disable auto-hinter.\n\tImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2,   // Indicates that the auto-hinter is preferred over the font's native hinter.\n\tImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3,   // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.\n\tImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4,   // Strong hinting algorithm that should only be used for monochrome output.\n\tImGuiFreeTypeBuilderFlags_Bold = 1 << 5,   // Styling: Should we artificially embolden the font?\n\tImGuiFreeTypeBuilderFlags_Oblique = 1 << 6,   // Styling: Should we slant the font, emulating italic style?\n\tImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7,   // Disable anti-aliasing. Combine this with MonoHinting for best results!\n\tImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8,   // Enable FreeType color-layered glyphs\n\tImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9    // Enable FreeType bitmap glyphs\n};\n\nnamespace ImGuiFreeType\n{\n\t// This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'.\n\t// If you need to dynamically select between multiple builders:\n\t// - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()'\n\t// - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data.\n\tIMGUI_API const ImFontBuilderIO* GetBuilderForFreeType();\n\n\t// Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE()\n\t// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired.\n\tIMGUI_API void                      SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);\n\n\t// Obsolete names (will be removed soon)\n\t// Prefer using '#define IMGUI_ENABLE_FREETYPE'\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tstatic inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); }\n#endif\n}\n"
  },
  {
    "path": "KBotExt/imgui/imgui_impl_dx11.cpp",
    "content": "// dear imgui: Renderer Backend for DirectX11\n// This needs to be used along with a Platform Backend (e.g. Win32)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!\n//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\n// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.\n// Read online: https://github.com/ocornut/imgui/tree/master/docs\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.\n//  2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).\n//  2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)\n//  2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.\n//  2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).\n//  2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.\n//  2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.\n//  2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.\n//  2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().\n//  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.\n//  2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.\n//  2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.\n//  2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.\n//  2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.\n//  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.\n//  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.\n//  2016-05-07: DirectX11: Disabling depth-write.\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_impl_dx11.h\"\n\n// DirectX\n#include <stdio.h>\n#include <d3d11.h>\n#include <d3dcompiler.h>\n#ifdef _MSC_VER\n#pragma comment(lib, \"d3dcompiler\") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.\n#endif\n\n// DirectX11 data\nstruct ImGui_ImplDX11_Data\n{\n\tID3D11Device* pd3dDevice;\n\tID3D11DeviceContext* pd3dDeviceContext;\n\tIDXGIFactory* pFactory;\n\tID3D11Buffer* pVB;\n\tID3D11Buffer* pIB;\n\tID3D11VertexShader* pVertexShader;\n\tID3D11InputLayout* pInputLayout;\n\tID3D11Buffer* pVertexConstantBuffer;\n\tID3D11PixelShader* pPixelShader;\n\tID3D11SamplerState* pFontSampler;\n\tID3D11ShaderResourceView* pFontTextureView;\n\tID3D11RasterizerState* pRasterizerState;\n\tID3D11BlendState* pBlendState;\n\tID3D11DepthStencilState* pDepthStencilState;\n\tint                         VertexBufferSize;\n\tint                         IndexBufferSize;\n\n\tImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }\n};\n\nstruct VERTEX_CONSTANT_BUFFER_DX11\n{\n\tfloat   mvp[4][4];\n};\n\n// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts\n// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.\nstatic ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()\n{\n\treturn ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;\n}\n\n// Functions\nstatic void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)\n{\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\n\t// Setup viewport\n\tD3D11_VIEWPORT vp;\n\tmemset(&vp, 0, sizeof(D3D11_VIEWPORT));\n\tvp.Width = draw_data->DisplaySize.x;\n\tvp.Height = draw_data->DisplaySize.y;\n\tvp.MinDepth = 0.0f;\n\tvp.MaxDepth = 1.0f;\n\tvp.TopLeftX = vp.TopLeftY = 0;\n\tctx->RSSetViewports(1, &vp);\n\n\t// Setup shader and vertex buffers\n\tunsigned int stride = sizeof(ImDrawVert);\n\tunsigned int offset = 0;\n\tctx->IASetInputLayout(bd->pInputLayout);\n\tctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);\n\tctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);\n\tctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\tctx->VSSetShader(bd->pVertexShader, nullptr, 0);\n\tctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);\n\tctx->PSSetShader(bd->pPixelShader, nullptr, 0);\n\tctx->PSSetSamplers(0, 1, &bd->pFontSampler);\n\tctx->GSSetShader(nullptr, nullptr, 0);\n\tctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..\n\tctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..\n\tctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..\n\n\t// Setup blend state\n\tconst float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };\n\tctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);\n\tctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);\n\tctx->RSSetState(bd->pRasterizerState);\n}\n\n// Render function\nvoid ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)\n{\n\t// Avoid rendering when minimized\n\tif (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)\n\t\treturn;\n\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tID3D11DeviceContext* ctx = bd->pd3dDeviceContext;\n\n\t// Create and grow vertex/index buffers if needed\n\tif (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)\n\t{\n\t\tif (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }\n\t\tbd->VertexBufferSize = draw_data->TotalVtxCount + 5000;\n\t\tD3D11_BUFFER_DESC desc;\n\t\tmemset(&desc, 0, sizeof(D3D11_BUFFER_DESC));\n\t\tdesc.Usage = D3D11_USAGE_DYNAMIC;\n\t\tdesc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);\n\t\tdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;\n\t\tdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n\t\tdesc.MiscFlags = 0;\n\t\tif (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)\n\t\t\treturn;\n\t}\n\tif (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)\n\t{\n\t\tif (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }\n\t\tbd->IndexBufferSize = draw_data->TotalIdxCount + 10000;\n\t\tD3D11_BUFFER_DESC desc;\n\t\tmemset(&desc, 0, sizeof(D3D11_BUFFER_DESC));\n\t\tdesc.Usage = D3D11_USAGE_DYNAMIC;\n\t\tdesc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);\n\t\tdesc.BindFlags = D3D11_BIND_INDEX_BUFFER;\n\t\tdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n\t\tif (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)\n\t\t\treturn;\n\t}\n\n\t// Upload vertex/index data into a single contiguous GPU buffer\n\tD3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;\n\tif (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)\n\t\treturn;\n\tif (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)\n\t\treturn;\n\tImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;\n\tImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;\n\tfor (int n = 0; n < draw_data->CmdListsCount; n++)\n\t{\n\t\tconst ImDrawList* cmd_list = draw_data->CmdLists[n];\n\t\tmemcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));\n\t\tmemcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));\n\t\tvtx_dst += cmd_list->VtxBuffer.Size;\n\t\tidx_dst += cmd_list->IdxBuffer.Size;\n\t}\n\tctx->Unmap(bd->pVB, 0);\n\tctx->Unmap(bd->pIB, 0);\n\n\t// Setup orthographic projection matrix into our constant buffer\n\t// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.\n\t{\n\t\tD3D11_MAPPED_SUBRESOURCE mapped_resource;\n\t\tif (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)\n\t\t\treturn;\n\t\tVERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;\n\t\tfloat L = draw_data->DisplayPos.x;\n\t\tfloat R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;\n\t\tfloat T = draw_data->DisplayPos.y;\n\t\tfloat B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;\n\t\tfloat mvp[4][4] =\n\t\t{\n\t\t\t{ 2.0f / (R - L),   0.0f,           0.0f,       0.0f },\n\t\t\t{ 0.0f,         2.0f / (T - B),     0.0f,       0.0f },\n\t\t\t{ 0.0f,         0.0f,           0.5f,       0.0f },\n\t\t\t{ (R + L) / (L - R),  (T + B) / (B - T),    0.5f,       1.0f },\n\t\t};\n\t\tmemcpy(&constant_buffer->mvp, mvp, sizeof(mvp));\n\t\tctx->Unmap(bd->pVertexConstantBuffer, 0);\n\t}\n\n\t// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)\n\tstruct BACKUP_DX11_STATE\n\t{\n\t\tUINT                        ScissorRectsCount, ViewportsCount;\n\t\tD3D11_RECT                  ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];\n\t\tD3D11_VIEWPORT              Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];\n\t\tID3D11RasterizerState* RS;\n\t\tID3D11BlendState* BlendState;\n\t\tFLOAT                       BlendFactor[4];\n\t\tUINT                        SampleMask;\n\t\tUINT                        StencilRef;\n\t\tID3D11DepthStencilState* DepthStencilState;\n\t\tID3D11ShaderResourceView* PSShaderResource;\n\t\tID3D11SamplerState* PSSampler;\n\t\tID3D11PixelShader* PS;\n\t\tID3D11VertexShader* VS;\n\t\tID3D11GeometryShader* GS;\n\t\tUINT                        PSInstancesCount, VSInstancesCount, GSInstancesCount;\n\t\tID3D11ClassInstance* PSInstances[256], * VSInstances[256], * GSInstances[256];   // 256 is max according to PSSetShader documentation\n\t\tD3D11_PRIMITIVE_TOPOLOGY    PrimitiveTopology;\n\t\tID3D11Buffer* IndexBuffer, * VertexBuffer, * VSConstantBuffer;\n\t\tUINT                        IndexBufferOffset, VertexBufferStride, VertexBufferOffset;\n\t\tDXGI_FORMAT                 IndexBufferFormat;\n\t\tID3D11InputLayout* InputLayout;\n\t};\n\tBACKUP_DX11_STATE old = {};\n\told.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;\n\tctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);\n\tctx->RSGetViewports(&old.ViewportsCount, old.Viewports);\n\tctx->RSGetState(&old.RS);\n\tctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);\n\tctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);\n\tctx->PSGetShaderResources(0, 1, &old.PSShaderResource);\n\tctx->PSGetSamplers(0, 1, &old.PSSampler);\n\told.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;\n\tctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);\n\tctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);\n\tctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);\n\tctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);\n\n\tctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);\n\tctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);\n\tctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);\n\tctx->IAGetInputLayout(&old.InputLayout);\n\n\t// Setup desired DX state\n\tImGui_ImplDX11_SetupRenderState(draw_data, ctx);\n\n\t// Render command lists\n\t// (Because we merged all buffers into a single one, we maintain our own offset into them)\n\tint global_idx_offset = 0;\n\tint global_vtx_offset = 0;\n\tImVec2 clip_off = draw_data->DisplayPos;\n\tfor (int n = 0; n < draw_data->CmdListsCount; n++)\n\t{\n\t\tconst ImDrawList* cmd_list = draw_data->CmdLists[n];\n\t\tfor (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n\t\t{\n\t\t\tconst ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n\t\t\tif (pcmd->UserCallback != nullptr)\n\t\t\t{\n\t\t\t\t// User callback, registered via ImDrawList::AddCallback()\n\t\t\t\t// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)\n\t\t\t\tif (pcmd->UserCallback == ImDrawCallback_ResetRenderState)\n\t\t\t\t\tImGui_ImplDX11_SetupRenderState(draw_data, ctx);\n\t\t\t\telse\n\t\t\t\t\tpcmd->UserCallback(cmd_list, pcmd);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Project scissor/clipping rectangles into framebuffer space\n\t\t\t\tImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);\n\t\t\t\tImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);\n\t\t\t\tif (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Apply scissor/clipping rectangle\n\t\t\t\tconst D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };\n\t\t\t\tctx->RSSetScissorRects(1, &r);\n\n\t\t\t\t// Bind texture, Draw\n\t\t\t\tID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();\n\t\t\t\tctx->PSSetShaderResources(0, 1, &texture_srv);\n\t\t\t\tctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);\n\t\t\t}\n\t\t}\n\t\tglobal_idx_offset += cmd_list->IdxBuffer.Size;\n\t\tglobal_vtx_offset += cmd_list->VtxBuffer.Size;\n\t}\n\n\t// Restore modified DX state\n\tctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);\n\tctx->RSSetViewports(old.ViewportsCount, old.Viewports);\n\tctx->RSSetState(old.RS); if (old.RS) old.RS->Release();\n\tctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();\n\tctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();\n\tctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();\n\tctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();\n\tctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();\n\tfor (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();\n\tctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();\n\tctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();\n\tctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();\n\tfor (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();\n\tctx->IASetPrimitiveTopology(old.PrimitiveTopology);\n\tctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();\n\tctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();\n\tctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();\n}\n\nstatic void ImGui_ImplDX11_CreateFontsTexture()\n{\n\t// Build texture atlas\n\tImGuiIO& io = ImGui::GetIO();\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tunsigned char* pixels;\n\tint width, height;\n\tio.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);\n\n\t// Upload texture to graphics system\n\t{\n\t\tD3D11_TEXTURE2D_DESC desc;\n\t\tZeroMemory(&desc, sizeof(desc));\n\t\tdesc.Width = width;\n\t\tdesc.Height = height;\n\t\tdesc.MipLevels = 1;\n\t\tdesc.ArraySize = 1;\n\t\tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\tdesc.SampleDesc.Count = 1;\n\t\tdesc.Usage = D3D11_USAGE_DEFAULT;\n\t\tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;\n\t\tdesc.CPUAccessFlags = 0;\n\n\t\tID3D11Texture2D* pTexture = nullptr;\n\t\tD3D11_SUBRESOURCE_DATA subResource;\n\t\tsubResource.pSysMem = pixels;\n\t\tsubResource.SysMemPitch = desc.Width * 4;\n\t\tsubResource.SysMemSlicePitch = 0;\n\t\tbd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);\n\t\tIM_ASSERT(pTexture != nullptr);\n\n\t\t// Create texture view\n\t\tD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;\n\t\tZeroMemory(&srvDesc, sizeof(srvDesc));\n\t\tsrvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\tsrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;\n\t\tsrvDesc.Texture2D.MipLevels = desc.MipLevels;\n\t\tsrvDesc.Texture2D.MostDetailedMip = 0;\n\t\tbd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);\n\t\tpTexture->Release();\n\t}\n\n\t// Store our identifier\n\tio.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);\n\n\t// Create texture sampler\n\t// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)\n\t{\n\t\tD3D11_SAMPLER_DESC desc;\n\t\tZeroMemory(&desc, sizeof(desc));\n\t\tdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;\n\t\tdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;\n\t\tdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;\n\t\tdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;\n\t\tdesc.MipLODBias = 0.f;\n\t\tdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;\n\t\tdesc.MinLOD = 0.f;\n\t\tdesc.MaxLOD = 0.f;\n\t\tbd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);\n\t}\n}\n\nbool    ImGui_ImplDX11_CreateDeviceObjects()\n{\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tif (!bd->pd3dDevice)\n\t\treturn false;\n\tif (bd->pFontSampler)\n\t\tImGui_ImplDX11_InvalidateDeviceObjects();\n\n\t// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)\n\t// If you would like to use this DX11 sample code but remove this dependency you can:\n\t//  1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]\n\t//  2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.\n\t// See https://github.com/ocornut/imgui/pull/638 for sources and details.\n\n\t// Create the vertex shader\n\t{\n\t\tstatic const char* vertexShader =\n\t\t\t\"cbuffer vertexBuffer : register(b0) \\\n            {\\\n              float4x4 ProjectionMatrix; \\\n            };\\\n            struct VS_INPUT\\\n            {\\\n              float2 pos : POSITION;\\\n              float4 col : COLOR0;\\\n              float2 uv  : TEXCOORD0;\\\n            };\\\n            \\\n            struct PS_INPUT\\\n            {\\\n              float4 pos : SV_POSITION;\\\n              float4 col : COLOR0;\\\n              float2 uv  : TEXCOORD0;\\\n            };\\\n            \\\n            PS_INPUT main(VS_INPUT input)\\\n            {\\\n              PS_INPUT output;\\\n              output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\\\n              output.col = input.col;\\\n              output.uv  = input.uv;\\\n              return output;\\\n            }\";\n\n\t\tID3DBlob* vertexShaderBlob;\n\t\tif (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, \"main\", \"vs_4_0\", 0, 0, &vertexShaderBlob, nullptr)))\n\t\t\treturn false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!\n\t\tif (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK)\n\t\t{\n\t\t\tvertexShaderBlob->Release();\n\t\t\treturn false;\n\t\t}\n\n\t\t// Create the input layout\n\t\tD3D11_INPUT_ELEMENT_DESC local_layout[] =\n\t\t{\n\t\t\t{ \"POSITION\", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },\n\t\t\t{ \"TEXCOORD\", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (UINT)IM_OFFSETOF(ImDrawVert, uv),  D3D11_INPUT_PER_VERTEX_DATA, 0 },\n\t\t\t{ \"COLOR\",    0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },\n\t\t};\n\t\tif (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)\n\t\t{\n\t\t\tvertexShaderBlob->Release();\n\t\t\treturn false;\n\t\t}\n\t\tvertexShaderBlob->Release();\n\n\t\t// Create the constant buffer\n\t\t{\n\t\t\tD3D11_BUFFER_DESC desc;\n\t\t\tdesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);\n\t\t\tdesc.Usage = D3D11_USAGE_DYNAMIC;\n\t\t\tdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;\n\t\t\tdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n\t\t\tdesc.MiscFlags = 0;\n\t\t\tbd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);\n\t\t}\n\t}\n\n\t// Create the pixel shader\n\t{\n\t\tstatic const char* pixelShader =\n\t\t\t\"struct PS_INPUT\\\n            {\\\n            float4 pos : SV_POSITION;\\\n            float4 col : COLOR0;\\\n            float2 uv  : TEXCOORD0;\\\n            };\\\n            sampler sampler0;\\\n            Texture2D texture0;\\\n            \\\n            float4 main(PS_INPUT input) : SV_Target\\\n            {\\\n            float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \\\n            return out_col; \\\n            }\";\n\n\t\tID3DBlob* pixelShaderBlob;\n\t\tif (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, \"main\", \"ps_4_0\", 0, 0, &pixelShaderBlob, nullptr)))\n\t\t\treturn false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!\n\t\tif (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK)\n\t\t{\n\t\t\tpixelShaderBlob->Release();\n\t\t\treturn false;\n\t\t}\n\t\tpixelShaderBlob->Release();\n\t}\n\n\t// Create the blending setup\n\t{\n\t\tD3D11_BLEND_DESC desc;\n\t\tZeroMemory(&desc, sizeof(desc));\n\t\tdesc.AlphaToCoverageEnable = false;\n\t\tdesc.RenderTarget[0].BlendEnable = true;\n\t\tdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;\n\t\tdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;\n\t\tdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;\n\t\tdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;\n\t\tdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;\n\t\tdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;\n\t\tdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;\n\t\tbd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);\n\t}\n\n\t// Create the rasterizer state\n\t{\n\t\tD3D11_RASTERIZER_DESC desc;\n\t\tZeroMemory(&desc, sizeof(desc));\n\t\tdesc.FillMode = D3D11_FILL_SOLID;\n\t\tdesc.CullMode = D3D11_CULL_NONE;\n\t\tdesc.ScissorEnable = true;\n\t\tdesc.DepthClipEnable = true;\n\t\tbd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);\n\t}\n\n\t// Create depth-stencil State\n\t{\n\t\tD3D11_DEPTH_STENCIL_DESC desc;\n\t\tZeroMemory(&desc, sizeof(desc));\n\t\tdesc.DepthEnable = false;\n\t\tdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;\n\t\tdesc.DepthFunc = D3D11_COMPARISON_ALWAYS;\n\t\tdesc.StencilEnable = false;\n\t\tdesc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;\n\t\tdesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;\n\t\tdesc.BackFace = desc.FrontFace;\n\t\tbd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);\n\t}\n\n\tImGui_ImplDX11_CreateFontsTexture();\n\n\treturn true;\n}\n\nvoid    ImGui_ImplDX11_InvalidateDeviceObjects()\n{\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tif (!bd->pd3dDevice)\n\t\treturn;\n\n\tif (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }\n\tif (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.\n\tif (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }\n\tif (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }\n\tif (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }\n\tif (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }\n\tif (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }\n\tif (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }\n\tif (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }\n\tif (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }\n\tif (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }\n}\n\nbool    ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tIM_ASSERT(io.BackendRendererUserData == nullptr && \"Already initialized a renderer backend!\");\n\n\t// Setup backend capabilities flags\n\tImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();\n\tio.BackendRendererUserData = (void*)bd;\n\tio.BackendRendererName = \"imgui_impl_dx11\";\n\tio.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n\n\t// Get factory from device\n\tIDXGIDevice* pDXGIDevice = nullptr;\n\tIDXGIAdapter* pDXGIAdapter = nullptr;\n\tIDXGIFactory* pFactory = nullptr;\n\n\tif (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)\n\t\tif (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)\n\t\t\tif (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)\n\t\t\t{\n\t\t\t\tbd->pd3dDevice = device;\n\t\t\t\tbd->pd3dDeviceContext = device_context;\n\t\t\t\tbd->pFactory = pFactory;\n\t\t\t}\n\tif (pDXGIDevice) pDXGIDevice->Release();\n\tif (pDXGIAdapter) pDXGIAdapter->Release();\n\tbd->pd3dDevice->AddRef();\n\tbd->pd3dDeviceContext->AddRef();\n\n\treturn true;\n}\n\nvoid ImGui_ImplDX11_Shutdown()\n{\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tIM_ASSERT(bd != nullptr && \"No renderer backend to shutdown, or already shutdown?\");\n\tImGuiIO& io = ImGui::GetIO();\n\n\tImGui_ImplDX11_InvalidateDeviceObjects();\n\tif (bd->pFactory) { bd->pFactory->Release(); }\n\tif (bd->pd3dDevice) { bd->pd3dDevice->Release(); }\n\tif (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }\n\tio.BackendRendererName = nullptr;\n\tio.BackendRendererUserData = nullptr;\n\tio.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;\n\tIM_DELETE(bd);\n}\n\nvoid ImGui_ImplDX11_NewFrame()\n{\n\tImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();\n\tIM_ASSERT(bd != nullptr && \"Did you call ImGui_ImplDX11_Init()?\");\n\n\tif (!bd->pFontSampler)\n\t\tImGui_ImplDX11_CreateDeviceObjects();\n}\n\n//-----------------------------------------------------------------------------\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imgui_impl_dx11.h",
    "content": "// dear imgui: Renderer Backend for DirectX11\n// This needs to be used along with a Platform Backend (e.g. Win32)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!\n//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\n// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.\n// Read online: https://github.com/ocornut/imgui/tree/master/docs\n\n#pragma once\n#include \"imgui.h\"      // IMGUI_IMPL_API\n#ifndef IMGUI_DISABLE\n\nstruct ID3D11Device;\nstruct ID3D11DeviceContext;\n\nIMGUI_IMPL_API bool     ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);\nIMGUI_IMPL_API void     ImGui_ImplDX11_Shutdown();\nIMGUI_IMPL_API void     ImGui_ImplDX11_NewFrame();\nIMGUI_IMPL_API void     ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);\n\n// Use if you want to reset your rendering device without losing Dear ImGui state.\nIMGUI_IMPL_API void     ImGui_ImplDX11_InvalidateDeviceObjects();\nIMGUI_IMPL_API bool     ImGui_ImplDX11_CreateDeviceObjects();\n\n#endif // #ifndef IMGUI_DISABLE\n"
  },
  {
    "path": "KBotExt/imgui/imgui_impl_win32.cpp",
    "content": "// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)\n// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)\n\n// Implemented features:\n//  [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)\n//  [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.\n//  [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]\n//  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.\n//  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\n// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.\n// Read online: https://github.com/ocornut/imgui/tree/master/docs\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_impl_win32.h\"\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <windows.h>\n#include <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()\n#include <tchar.h>\n#include <dwmapi.h>\n\n// Configuration flags to add in your imconfig.h file:\n//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD              // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.\n\n// Using XInput for gamepad (will load DLL dynamically)\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n#include <xinput.h>\ntypedef DWORD(WINAPI* PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);\ntypedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*);\n#endif\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2023-04-19: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw Win32/Winapi with OpenGL. (#3218)\n//  2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen. (#2702)\n//  2023-02-15: Inputs: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse position over non-client area (e.g. OS decorations) when app is not focused. (#6045, #6162)\n//  2023-02-02: Inputs: Flipping WM_MOUSEHWHEEL (horizontal mouse-wheel) value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)\n//  2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.\n//  2022-09-28: Inputs: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode).\n//  2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).\n//  2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.\n//  2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].\n//  2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).\n//  2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates.\n//  2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.\n//  2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.\n//  2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.\n//  2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.\n//  2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.\n//  2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.\n//  2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).\n//  2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).\n//  2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).\n//  2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).\n//  2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).\n//  2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.\n//  2021-01-25: Inputs: Dynamically loading XInput DLL.\n//  2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.\n//  2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)\n//  2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.\n//  2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.\n//  2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.\n//  2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().\n//  2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.\n//  2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.\n//  2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).\n//  2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.\n//  2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.\n//  2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).\n//  2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.\n//  2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.\n//  2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).\n//  2018-02-06: Inputs: Added mapping for ImGuiKey_Space.\n//  2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).\n//  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.\n//  2018-01-20: Inputs: Added Horizontal Mouse Wheel support.\n//  2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.\n//  2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.\n//  2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.\n//  2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.\n//  2016-11-12: Inputs: Only call Win32 ::SetCursor(nullptr) when io.MouseDrawCursor is set.\n\nstruct ImGui_ImplWin32_Data\n{\n\tHWND                        hWnd;\n\tHWND                        MouseHwnd;\n\tint                         MouseTrackedArea;   // 0: not tracked, 1: client are, 2: non-client area\n\tint                         MouseButtonsDown;\n\tINT64                       Time;\n\tINT64                       TicksPerSecond;\n\tImGuiMouseCursor            LastMouseCursor;\n\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\tbool                        HasGamepad;\n\tbool                        WantUpdateHasGamepad;\n\tHMODULE                     XInputDLL;\n\tPFN_XInputGetCapabilities   XInputGetCapabilities;\n\tPFN_XInputGetState          XInputGetState;\n#endif\n\n\tImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); }\n};\n\n// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts\n// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.\n// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.\n// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.\nstatic ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()\n{\n\treturn ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;\n}\n\n// Functions\nstatic bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tIM_ASSERT(io.BackendPlatformUserData == nullptr && \"Already initialized a platform backend!\");\n\n\tINT64 perf_frequency, perf_counter;\n\tif (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency))\n\t\treturn false;\n\tif (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))\n\t\treturn false;\n\n\t// Setup backend capabilities flags\n\tImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();\n\tio.BackendPlatformUserData = (void*)bd;\n\tio.BackendPlatformName = \"imgui_impl_win32\";\n\tio.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;         // We can honor GetMouseCursor() values (optional)\n\tio.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used)\n\n\tbd->hWnd = (HWND)hwnd;\n\tbd->TicksPerSecond = perf_frequency;\n\tbd->Time = perf_counter;\n\tbd->LastMouseCursor = ImGuiMouseCursor_COUNT;\n\n\t// Set platform dependent data in viewport\n\tImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd;\n\tIM_UNUSED(platform_has_own_dc); // Used in 'docking' branch\n\n\t// Dynamically load XInput library\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\tbd->WantUpdateHasGamepad = true;\n\tconst char* xinput_dll_names[] =\n\t{\n\t\t\"xinput1_4.dll\",   // Windows 8+\n\t\t\"xinput1_3.dll\",   // DirectX SDK\n\t\t\"xinput9_1_0.dll\", // Windows Vista, Windows 7\n\t\t\"xinput1_2.dll\",   // DirectX SDK\n\t\t\"xinput1_1.dll\"    // DirectX SDK\n\t};\n\tfor (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)\n\t\tif (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))\n\t\t{\n\t\t\tbd->XInputDLL = dll;\n\t\t\tbd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, \"XInputGetCapabilities\");\n\t\t\tbd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, \"XInputGetState\");\n\t\t\tbreak;\n\t\t}\n#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\n\treturn true;\n}\n\nIMGUI_IMPL_API bool     ImGui_ImplWin32_Init(void* hwnd)\n{\n\treturn ImGui_ImplWin32_InitEx(hwnd, false);\n}\n\nIMGUI_IMPL_API bool     ImGui_ImplWin32_InitForOpenGL(void* hwnd)\n{\n\t// OpenGL needs CS_OWNDC\n\treturn ImGui_ImplWin32_InitEx(hwnd, true);\n}\n\nvoid    ImGui_ImplWin32_Shutdown()\n{\n\tImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();\n\tIM_ASSERT(bd != nullptr && \"No platform backend to shutdown, or already shutdown?\");\n\tImGuiIO& io = ImGui::GetIO();\n\n\t// Unload XInput library\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\tif (bd->XInputDLL)\n\t\t::FreeLibrary(bd->XInputDLL);\n#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\n\tio.BackendPlatformName = nullptr;\n\tio.BackendPlatformUserData = nullptr;\n\tio.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);\n\tIM_DELETE(bd);\n}\n\nstatic bool ImGui_ImplWin32_UpdateMouseCursor()\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tif (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)\n\t\treturn false;\n\n\tImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();\n\tif (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)\n\t{\n\t\t// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor\n\t\t::SetCursor(nullptr);\n\t}\n\telse\n\t{\n\t\t// Show OS mouse cursor\n\t\tLPTSTR win32_cursor = IDC_ARROW;\n\t\tswitch (imgui_cursor)\n\t\t{\n\t\tcase ImGuiMouseCursor_Arrow:        win32_cursor = IDC_ARROW; break;\n\t\tcase ImGuiMouseCursor_TextInput:    win32_cursor = IDC_IBEAM; break;\n\t\tcase ImGuiMouseCursor_ResizeAll:    win32_cursor = IDC_SIZEALL; break;\n\t\tcase ImGuiMouseCursor_ResizeEW:     win32_cursor = IDC_SIZEWE; break;\n\t\tcase ImGuiMouseCursor_ResizeNS:     win32_cursor = IDC_SIZENS; break;\n\t\tcase ImGuiMouseCursor_ResizeNESW:   win32_cursor = IDC_SIZENESW; break;\n\t\tcase ImGuiMouseCursor_ResizeNWSE:   win32_cursor = IDC_SIZENWSE; break;\n\t\tcase ImGuiMouseCursor_Hand:         win32_cursor = IDC_HAND; break;\n\t\tcase ImGuiMouseCursor_NotAllowed:   win32_cursor = IDC_NO; break;\n\t\t}\n\t\t::SetCursor(::LoadCursor(nullptr, win32_cursor));\n\t}\n\treturn true;\n}\n\nstatic bool IsVkDown(int vk)\n{\n\treturn (::GetKeyState(vk) & 0x8000) != 0;\n}\n\nstatic void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tio.AddKeyEvent(key, down);\n\tio.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)\n\tIM_UNUSED(native_scancode);\n}\n\nstatic void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()\n{\n\t// Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.\n\tif (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))\n\t\tImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);\n\tif (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))\n\t\tImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);\n\n\t// Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).\n\tif (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))\n\t\tImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);\n\tif (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))\n\t\tImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);\n}\n\nstatic void ImGui_ImplWin32_UpdateKeyModifiers()\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tio.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL));\n\tio.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT));\n\tio.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU));\n\tio.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_APPS));\n}\n\nstatic void ImGui_ImplWin32_UpdateMouseData()\n{\n\tImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();\n\tImGuiIO& io = ImGui::GetIO();\n\tIM_ASSERT(bd->hWnd != 0);\n\n\tHWND focused_window = ::GetForegroundWindow();\n\tconst bool is_app_focused = (focused_window == bd->hWnd);\n\tif (is_app_focused)\n\t{\n\t\t// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)\n\t\tif (io.WantSetMousePos)\n\t\t{\n\t\t\tPOINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };\n\t\t\tif (::ClientToScreen(bd->hWnd, &pos))\n\t\t\t\t::SetCursorPos(pos.x, pos.y);\n\t\t}\n\n\t\t// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)\n\t\t// This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE\n\t\tif (!io.WantSetMousePos && bd->MouseTrackedArea == 0)\n\t\t{\n\t\t\tPOINT pos;\n\t\t\tif (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))\n\t\t\t\tio.AddMousePosEvent((float)pos.x, (float)pos.y);\n\t\t}\n\t}\n}\n\n// Gamepad navigation mapping\nstatic void ImGui_ImplWin32_UpdateGamepads()\n{\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\tImGuiIO& io = ImGui::GetIO();\n\tImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();\n\t//if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.\n\t//    return;\n\n\t// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.\n\t// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.\n\tif (bd->WantUpdateHasGamepad)\n\t{\n\t\tXINPUT_CAPABILITIES caps = {};\n\t\tbd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;\n\t\tbd->WantUpdateHasGamepad = false;\n\t}\n\n\tio.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;\n\tXINPUT_STATE xinput_state;\n\tXINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;\n\tif (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)\n\t\treturn;\n\tio.BackendFlags |= ImGuiBackendFlags_HasGamepad;\n\n#define IM_SATURATE(V)                      (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)\n#define MAP_BUTTON(KEY_NO, BUTTON_ENUM)     { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }\n#define MAP_ANALOG(KEY_NO, VALUE, V0, V1)   { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }\n\tMAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);\n\tMAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);\n\tMAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);\n\tMAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);\n\tMAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);\n\tMAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);\n\tMAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);\n\tMAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);\n\tMAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);\n\tMAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);\n\tMAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);\n\tMAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);\n\tMAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);\n\tMAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);\n\tMAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);\n\tMAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);\n\tMAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);\n\tMAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);\n\tMAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);\n\tMAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);\n\tMAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);\n\tMAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);\n\tMAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);\n\tMAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);\n#undef MAP_BUTTON\n#undef MAP_ANALOG\n#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n}\n\nvoid    ImGui_ImplWin32_NewFrame()\n{\n\tImGuiIO& io = ImGui::GetIO();\n\tImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();\n\tIM_ASSERT(bd != nullptr && \"Did you call ImGui_ImplWin32_Init()?\");\n\n\t// Setup display size (every frame to accommodate for window resizing)\n\tRECT rect = { 0, 0, 0, 0 };\n\t::GetClientRect(bd->hWnd, &rect);\n\tio.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));\n\n\t// Setup time step\n\tINT64 current_time = 0;\n\t::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);\n\tio.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond;\n\tbd->Time = current_time;\n\n\t// Update OS mouse position\n\tImGui_ImplWin32_UpdateMouseData();\n\n\t// Process workarounds for known Windows key handling issues\n\tImGui_ImplWin32_ProcessKeyEventsWorkarounds();\n\n\t// Update OS mouse cursor with the cursor requested by imgui\n\tImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();\n\tif (bd->LastMouseCursor != mouse_cursor)\n\t{\n\t\tbd->LastMouseCursor = mouse_cursor;\n\t\tImGui_ImplWin32_UpdateMouseCursor();\n\t}\n\n\t// Update game controllers (if enabled and available)\n\tImGui_ImplWin32_UpdateGamepads();\n}\n\n// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)\n#define IM_VK_KEYPAD_ENTER      (VK_RETURN + 256)\n\n// Map VK_xxx to ImGuiKey_xxx.\nstatic ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)\n{\n\tswitch (wParam)\n\t{\n\tcase VK_TAB: return ImGuiKey_Tab;\n\tcase VK_LEFT: return ImGuiKey_LeftArrow;\n\tcase VK_RIGHT: return ImGuiKey_RightArrow;\n\tcase VK_UP: return ImGuiKey_UpArrow;\n\tcase VK_DOWN: return ImGuiKey_DownArrow;\n\tcase VK_PRIOR: return ImGuiKey_PageUp;\n\tcase VK_NEXT: return ImGuiKey_PageDown;\n\tcase VK_HOME: return ImGuiKey_Home;\n\tcase VK_END: return ImGuiKey_End;\n\tcase VK_INSERT: return ImGuiKey_Insert;\n\tcase VK_DELETE: return ImGuiKey_Delete;\n\tcase VK_BACK: return ImGuiKey_Backspace;\n\tcase VK_SPACE: return ImGuiKey_Space;\n\tcase VK_RETURN: return ImGuiKey_Enter;\n\tcase VK_ESCAPE: return ImGuiKey_Escape;\n\tcase VK_OEM_7: return ImGuiKey_Apostrophe;\n\tcase VK_OEM_COMMA: return ImGuiKey_Comma;\n\tcase VK_OEM_MINUS: return ImGuiKey_Minus;\n\tcase VK_OEM_PERIOD: return ImGuiKey_Period;\n\tcase VK_OEM_2: return ImGuiKey_Slash;\n\tcase VK_OEM_1: return ImGuiKey_Semicolon;\n\tcase VK_OEM_PLUS: return ImGuiKey_Equal;\n\tcase VK_OEM_4: return ImGuiKey_LeftBracket;\n\tcase VK_OEM_5: return ImGuiKey_Backslash;\n\tcase VK_OEM_6: return ImGuiKey_RightBracket;\n\tcase VK_OEM_3: return ImGuiKey_GraveAccent;\n\tcase VK_CAPITAL: return ImGuiKey_CapsLock;\n\tcase VK_SCROLL: return ImGuiKey_ScrollLock;\n\tcase VK_NUMLOCK: return ImGuiKey_NumLock;\n\tcase VK_SNAPSHOT: return ImGuiKey_PrintScreen;\n\tcase VK_PAUSE: return ImGuiKey_Pause;\n\tcase VK_NUMPAD0: return ImGuiKey_Keypad0;\n\tcase VK_NUMPAD1: return ImGuiKey_Keypad1;\n\tcase VK_NUMPAD2: return ImGuiKey_Keypad2;\n\tcase VK_NUMPAD3: return ImGuiKey_Keypad3;\n\tcase VK_NUMPAD4: return ImGuiKey_Keypad4;\n\tcase VK_NUMPAD5: return ImGuiKey_Keypad5;\n\tcase VK_NUMPAD6: return ImGuiKey_Keypad6;\n\tcase VK_NUMPAD7: return ImGuiKey_Keypad7;\n\tcase VK_NUMPAD8: return ImGuiKey_Keypad8;\n\tcase VK_NUMPAD9: return ImGuiKey_Keypad9;\n\tcase VK_DECIMAL: return ImGuiKey_KeypadDecimal;\n\tcase VK_DIVIDE: return ImGuiKey_KeypadDivide;\n\tcase VK_MULTIPLY: return ImGuiKey_KeypadMultiply;\n\tcase VK_SUBTRACT: return ImGuiKey_KeypadSubtract;\n\tcase VK_ADD: return ImGuiKey_KeypadAdd;\n\tcase IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;\n\tcase VK_LSHIFT: return ImGuiKey_LeftShift;\n\tcase VK_LCONTROL: return ImGuiKey_LeftCtrl;\n\tcase VK_LMENU: return ImGuiKey_LeftAlt;\n\tcase VK_LWIN: return ImGuiKey_LeftSuper;\n\tcase VK_RSHIFT: return ImGuiKey_RightShift;\n\tcase VK_RCONTROL: return ImGuiKey_RightCtrl;\n\tcase VK_RMENU: return ImGuiKey_RightAlt;\n\tcase VK_RWIN: return ImGuiKey_RightSuper;\n\tcase VK_APPS: return ImGuiKey_Menu;\n\tcase '0': return ImGuiKey_0;\n\tcase '1': return ImGuiKey_1;\n\tcase '2': return ImGuiKey_2;\n\tcase '3': return ImGuiKey_3;\n\tcase '4': return ImGuiKey_4;\n\tcase '5': return ImGuiKey_5;\n\tcase '6': return ImGuiKey_6;\n\tcase '7': return ImGuiKey_7;\n\tcase '8': return ImGuiKey_8;\n\tcase '9': return ImGuiKey_9;\n\tcase 'A': return ImGuiKey_A;\n\tcase 'B': return ImGuiKey_B;\n\tcase 'C': return ImGuiKey_C;\n\tcase 'D': return ImGuiKey_D;\n\tcase 'E': return ImGuiKey_E;\n\tcase 'F': return ImGuiKey_F;\n\tcase 'G': return ImGuiKey_G;\n\tcase 'H': return ImGuiKey_H;\n\tcase 'I': return ImGuiKey_I;\n\tcase 'J': return ImGuiKey_J;\n\tcase 'K': return ImGuiKey_K;\n\tcase 'L': return ImGuiKey_L;\n\tcase 'M': return ImGuiKey_M;\n\tcase 'N': return ImGuiKey_N;\n\tcase 'O': return ImGuiKey_O;\n\tcase 'P': return ImGuiKey_P;\n\tcase 'Q': return ImGuiKey_Q;\n\tcase 'R': return ImGuiKey_R;\n\tcase 'S': return ImGuiKey_S;\n\tcase 'T': return ImGuiKey_T;\n\tcase 'U': return ImGuiKey_U;\n\tcase 'V': return ImGuiKey_V;\n\tcase 'W': return ImGuiKey_W;\n\tcase 'X': return ImGuiKey_X;\n\tcase 'Y': return ImGuiKey_Y;\n\tcase 'Z': return ImGuiKey_Z;\n\tcase VK_F1: return ImGuiKey_F1;\n\tcase VK_F2: return ImGuiKey_F2;\n\tcase VK_F3: return ImGuiKey_F3;\n\tcase VK_F4: return ImGuiKey_F4;\n\tcase VK_F5: return ImGuiKey_F5;\n\tcase VK_F6: return ImGuiKey_F6;\n\tcase VK_F7: return ImGuiKey_F7;\n\tcase VK_F8: return ImGuiKey_F8;\n\tcase VK_F9: return ImGuiKey_F9;\n\tcase VK_F10: return ImGuiKey_F10;\n\tcase VK_F11: return ImGuiKey_F11;\n\tcase VK_F12: return ImGuiKey_F12;\n\tdefault: return ImGuiKey_None;\n\t}\n}\n\n// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.\n#ifndef WM_MOUSEHWHEEL\n#define WM_MOUSEHWHEEL 0x020E\n#endif\n#ifndef DBT_DEVNODES_CHANGED\n#define DBT_DEVNODES_CHANGED 0x0007\n#endif\n\n// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)\n// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.\n// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.\n// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.\n// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.\n// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.\n// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.\n// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.\n#if 0\n// Copy this line into your .cpp file to forward declare the function.\nextern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);\n#endif\n\n// See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages\n// Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this.\nstatic ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()\n{\n\tLPARAM extra_info = ::GetMessageExtraInfo();\n\tif ((extra_info & 0xFFFFFF80) == 0xFF515700)\n\t\treturn ImGuiMouseSource_Pen;\n\tif ((extra_info & 0xFFFFFF80) == 0xFF515780)\n\t\treturn ImGuiMouseSource_TouchScreen;\n\treturn ImGuiMouseSource_Mouse;\n}\n\nIMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\n{\n\tif (ImGui::GetCurrentContext() == nullptr)\n\t\treturn 0;\n\n\tImGuiIO& io = ImGui::GetIO();\n\tImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();\n\n\tswitch (msg)\n\t{\n\tcase WM_MOUSEMOVE:\n\tcase WM_NCMOUSEMOVE:\n\t{\n\t\t// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events\n\t\tImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();\n\t\tconst int area = (msg == WM_MOUSEMOVE) ? 1 : 2;\n\t\tbd->MouseHwnd = hwnd;\n\t\tif (bd->MouseTrackedArea != area)\n\t\t{\n\t\t\tTRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 };\n\t\t\tTRACKMOUSEEVENT tme_track = { sizeof(tme_track), (DWORD)((area == 2) ? (TME_LEAVE | TME_NONCLIENT) : TME_LEAVE), hwnd, 0 };\n\t\t\tif (bd->MouseTrackedArea != 0)\n\t\t\t\t::TrackMouseEvent(&tme_cancel);\n\t\t\t::TrackMouseEvent(&tme_track);\n\t\t\tbd->MouseTrackedArea = area;\n\t\t}\n\t\tPOINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };\n\t\tif (msg == WM_NCMOUSEMOVE && ::ScreenToClient(hwnd, &mouse_pos) == FALSE) // WM_NCMOUSEMOVE are provided in absolute coordinates.\n\t\t\tbreak;\n\t\tio.AddMouseSourceEvent(mouse_source);\n\t\tio.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);\n\t\tbreak;\n\t}\n\tcase WM_MOUSELEAVE:\n\tcase WM_NCMOUSELEAVE:\n\t{\n\t\tconst int area = (msg == WM_MOUSELEAVE) ? 1 : 2;\n\t\tif (bd->MouseTrackedArea == area)\n\t\t{\n\t\t\tif (bd->MouseHwnd == hwnd)\n\t\t\t\tbd->MouseHwnd = nullptr;\n\t\t\tbd->MouseTrackedArea = 0;\n\t\t\tio.AddMousePosEvent(-FLT_MAX, -FLT_MAX);\n\t\t}\n\t\tbreak;\n\t}\n\tcase WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:\n\tcase WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:\n\tcase WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:\n\tcase WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:\n\t{\n\t\tImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();\n\t\tint button = 0;\n\t\tif (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }\n\t\tif (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }\n\t\tif (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }\n\t\tif (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }\n\t\tif (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr)\n\t\t\t::SetCapture(hwnd);\n\t\tbd->MouseButtonsDown |= 1 << button;\n\t\tio.AddMouseSourceEvent(mouse_source);\n\t\tio.AddMouseButtonEvent(button, true);\n\t\treturn 0;\n\t}\n\tcase WM_LBUTTONUP:\n\tcase WM_RBUTTONUP:\n\tcase WM_MBUTTONUP:\n\tcase WM_XBUTTONUP:\n\t{\n\t\tImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();\n\t\tint button = 0;\n\t\tif (msg == WM_LBUTTONUP) { button = 0; }\n\t\tif (msg == WM_RBUTTONUP) { button = 1; }\n\t\tif (msg == WM_MBUTTONUP) { button = 2; }\n\t\tif (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }\n\t\tbd->MouseButtonsDown &= ~(1 << button);\n\t\tif (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd)\n\t\t\t::ReleaseCapture();\n\t\tio.AddMouseSourceEvent(mouse_source);\n\t\tio.AddMouseButtonEvent(button, false);\n\t\treturn 0;\n\t}\n\tcase WM_MOUSEWHEEL:\n\t\tio.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);\n\t\treturn 0;\n\tcase WM_MOUSEHWHEEL:\n\t\tio.AddMouseWheelEvent(-(float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f);\n\t\treturn 0;\n\tcase WM_KEYDOWN:\n\tcase WM_KEYUP:\n\tcase WM_SYSKEYDOWN:\n\tcase WM_SYSKEYUP:\n\t{\n\t\tconst bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);\n\t\tif (wParam < 256)\n\t\t{\n\t\t\t// Submit modifiers\n\t\t\tImGui_ImplWin32_UpdateKeyModifiers();\n\n\t\t\t// Obtain virtual key code\n\t\t\t// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)\n\t\t\tint vk = (int)wParam;\n\t\t\tif ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))\n\t\t\t\tvk = IM_VK_KEYPAD_ENTER;\n\n\t\t\t// Submit key event\n\t\t\tconst ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);\n\t\t\tconst int scancode = (int)LOBYTE(HIWORD(lParam));\n\t\t\tif (key != ImGuiKey_None)\n\t\t\t\tImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);\n\n\t\t\t// Submit individual left/right modifier events\n\t\t\tif (vk == VK_SHIFT)\n\t\t\t{\n\t\t\t\t// Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()\n\t\t\t\tif (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }\n\t\t\t\tif (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }\n\t\t\t}\n\t\t\telse if (vk == VK_CONTROL)\n\t\t\t{\n\t\t\t\tif (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); }\n\t\t\t\tif (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); }\n\t\t\t}\n\t\t\telse if (vk == VK_MENU)\n\t\t\t{\n\t\t\t\tif (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }\n\t\t\t\tif (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\tcase WM_SETFOCUS:\n\tcase WM_KILLFOCUS:\n\t\tio.AddFocusEvent(msg == WM_SETFOCUS);\n\t\treturn 0;\n\tcase WM_CHAR:\n\t\tif (::IsWindowUnicode(hwnd))\n\t\t{\n\t\t\t// You can also use ToAscii()+GetKeyboardState() to retrieve characters.\n\t\t\tif (wParam > 0 && wParam < 0x10000)\n\t\t\t\tio.AddInputCharacterUTF16((unsigned short)wParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\twchar_t wch = 0;\n\t\t\t::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char*)&wParam, 1, &wch, 1);\n\t\t\tio.AddInputCharacter(wch);\n\t\t}\n\t\treturn 0;\n\tcase WM_SETCURSOR:\n\t\t// This is required to restore cursor when transitioning from e.g resize borders to client area.\n\t\tif (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())\n\t\t\treturn 1;\n\t\treturn 0;\n\tcase WM_DEVICECHANGE:\n#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD\n\t\tif ((UINT)wParam == DBT_DEVNODES_CHANGED)\n\t\t\tbd->WantUpdateHasGamepad = true;\n#endif\n\t\treturn 0;\n\t}\n\treturn 0;\n}\n\n//--------------------------------------------------------------------------------------------------------\n// DPI-related helpers (optional)\n//--------------------------------------------------------------------------------------------------------\n// - Use to enable DPI awareness without having to create an application manifest.\n// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.\n// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.\n//   but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,\n//   neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.\n//---------------------------------------------------------------------------------------------------------\n// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.\n// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.\n// If you are trying to implement your own backend for your own engine, you may ignore that noise.\n//---------------------------------------------------------------------------------------------------------\n\n// Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they\n// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200\nstatic BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)\n{\n\ttypedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);\n\tstatic PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = nullptr;\n\tif (RtlVerifyVersionInfoFn == nullptr)\n\t\tif (HMODULE ntdllModule = ::GetModuleHandleA(\"ntdll.dll\"))\n\t\t\tRtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, \"RtlVerifyVersionInfo\");\n\tif (RtlVerifyVersionInfoFn == nullptr)\n\t\treturn FALSE;\n\n\tRTL_OSVERSIONINFOEXW versionInfo = { };\n\tULONGLONG conditionMask = 0;\n\tversionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);\n\tversionInfo.dwMajorVersion = major;\n\tversionInfo.dwMinorVersion = minor;\n\tVER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);\n\tVER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);\n\treturn (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;\n}\n\n#define _IsWindowsVistaOrGreater()   _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA\n#define _IsWindows8OrGreater()       _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8\n#define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE\n#define _IsWindows10OrGreater()      _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10\n\n#ifndef DPI_ENUMS_DECLARED\ntypedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;\ntypedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;\n#endif\n#ifndef _DPI_AWARENESS_CONTEXTS_\nDECLARE_HANDLE(DPI_AWARENESS_CONTEXT);\n#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE    (DPI_AWARENESS_CONTEXT)-3\n#endif\n#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2\n#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4\n#endif\ntypedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);                     // Shcore.lib + dll, Windows 8.1+\ntypedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);        // Shcore.lib + dll, Windows 8.1+\ntypedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)\n\n// Helper function to enable DPI awareness without setting up a manifest\nvoid ImGui_ImplWin32_EnableDpiAwareness()\n{\n\tif (_IsWindows10OrGreater())\n\t{\n\t\tstatic HINSTANCE user32_dll = ::LoadLibraryA(\"user32.dll\"); // Reference counted per-process\n\t\tif (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, \"SetThreadDpiAwarenessContext\"))\n\t\t{\n\t\t\tSetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);\n\t\t\treturn;\n\t\t}\n\t}\n\tif (_IsWindows8Point1OrGreater())\n\t{\n\t\tstatic HINSTANCE shcore_dll = ::LoadLibraryA(\"shcore.dll\"); // Reference counted per-process\n\t\tif (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, \"SetProcessDpiAwareness\"))\n\t\t{\n\t\t\tSetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);\n\t\t\treturn;\n\t\t}\n\t}\n#if _WIN32_WINNT >= 0x0600\n\t::SetProcessDPIAware();\n#endif\n}\n\n#if defined(_MSC_VER) && !defined(NOGDI)\n#pragma comment(lib, \"gdi32\")   // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'\n#endif\n\nfloat ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)\n{\n\tUINT xdpi = 96, ydpi = 96;\n\tif (_IsWindows8Point1OrGreater())\n\t{\n\t\tstatic HINSTANCE shcore_dll = ::LoadLibraryA(\"shcore.dll\"); // Reference counted per-process\n\t\tstatic PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr;\n\t\tif (GetDpiForMonitorFn == nullptr && shcore_dll != nullptr)\n\t\t\tGetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, \"GetDpiForMonitor\");\n\t\tif (GetDpiForMonitorFn != nullptr)\n\t\t{\n\t\t\tGetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);\n\t\t\tIM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!\n\t\t\treturn xdpi / 96.0f;\n\t\t}\n\t}\n#ifndef NOGDI\n\tconst HDC dc = ::GetDC(nullptr);\n\txdpi = ::GetDeviceCaps(dc, LOGPIXELSX);\n\tydpi = ::GetDeviceCaps(dc, LOGPIXELSY);\n\tIM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!\n\t::ReleaseDC(nullptr, dc);\n#endif\n\treturn xdpi / 96.0f;\n}\n\nfloat ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)\n{\n\tHMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);\n\treturn ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);\n}\n\n//---------------------------------------------------------------------------------------------------------\n// Transparency related helpers (optional)\n//--------------------------------------------------------------------------------------------------------\n\n#if defined(_MSC_VER)\n#pragma comment(lib, \"dwmapi\")  // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'\n#endif\n\n// [experimental]\n// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c\n// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)\nvoid ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)\n{\n\tif (!_IsWindowsVistaOrGreater())\n\t\treturn;\n\n\tBOOL composition;\n\tif (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)\n\t\treturn;\n\n\tBOOL opaque;\n\tDWORD color;\n\tif (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))\n\t{\n\t\tHRGN region = ::CreateRectRgn(0, 0, -1, -1);\n\t\tDWM_BLURBEHIND bb = {};\n\t\tbb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;\n\t\tbb.hRgnBlur = region;\n\t\tbb.fEnable = TRUE;\n\t\t::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);\n\t\t::DeleteObject(region);\n\t}\n\telse\n\t{\n\t\tDWM_BLURBEHIND bb = {};\n\t\tbb.dwFlags = DWM_BB_ENABLE;\n\t\t::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);\n\t}\n}\n\n//---------------------------------------------------------------------------------------------------------\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imgui_impl_win32.h",
    "content": "// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)\n// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)\n\n// Implemented features:\n//  [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)\n//  [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.\n//  [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]\n//  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.\n//  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\n// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.\n// Read online: https://github.com/ocornut/imgui/tree/master/docs\n\n#pragma once\n#include \"imgui.h\"      // IMGUI_IMPL_API\n#ifndef IMGUI_DISABLE\n\nIMGUI_IMPL_API bool     ImGui_ImplWin32_Init(void* hwnd);\nIMGUI_IMPL_API bool     ImGui_ImplWin32_InitForOpenGL(void* hwnd);\nIMGUI_IMPL_API void     ImGui_ImplWin32_Shutdown();\nIMGUI_IMPL_API void     ImGui_ImplWin32_NewFrame();\n\n// Win32 message handler your application need to call.\n// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.\n// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.\n// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.\n\n#if 0\nextern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);\n#endif\n\n// DPI-related helpers (optional)\n// - Use to enable DPI awareness without having to create an application manifest.\n// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.\n// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.\n//   but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,\n//   neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.\nIMGUI_IMPL_API void     ImGui_ImplWin32_EnableDpiAwareness();\nIMGUI_IMPL_API float    ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd);       // HWND hwnd\nIMGUI_IMPL_API float    ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor\n\n// Transparency related helpers (optional) [experimental]\n// - Use to enable alpha compositing transparency with the desktop.\n// - Use together with e.g. clearing your framebuffer with zero-alpha.\nIMGUI_IMPL_API void     ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd);   // HWND hwnd\n\n#endif // #ifndef IMGUI_DISABLE\n"
  },
  {
    "path": "KBotExt/imgui/imgui_internal.h",
    "content": "// dear imgui, v1.89.9\n// (internal structures/api)\n\n// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.\n// To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use:\n/*\n#define IMGUI_DEFINE_MATH_OPERATORS\n#include \"imgui_internal.h\"\n*/\n\n/*\n\nIndex of this file:\n\n// [SECTION] Header mess\n// [SECTION] Forward declarations\n// [SECTION] Context pointer\n// [SECTION] STB libraries includes\n// [SECTION] Macros\n// [SECTION] Generic helpers\n// [SECTION] ImDrawList support\n// [SECTION] Widgets support: flags, enums, data structures\n// [SECTION] Inputs support\n// [SECTION] Clipper support\n// [SECTION] Navigation support\n// [SECTION] Columns support\n// [SECTION] Multi-select support\n// [SECTION] Docking support\n// [SECTION] Viewport support\n// [SECTION] Settings support\n// [SECTION] Localization support\n// [SECTION] Metrics, Debug tools\n// [SECTION] Generic context hooks\n// [SECTION] ImGuiContext (main imgui context)\n// [SECTION] ImGuiWindowTempData, ImGuiWindow\n// [SECTION] Tab bar, Tab item support\n// [SECTION] Table support\n// [SECTION] ImGui internal API\n// [SECTION] ImFontAtlas internal API\n// [SECTION] Test Engine specific hooks (imgui_test_engine)\n\n*/\n\n#pragma once\n#ifndef IMGUI_DISABLE\n\n//-----------------------------------------------------------------------------\n// [SECTION] Header mess\n//-----------------------------------------------------------------------------\n\n#ifndef IMGUI_VERSION\n#include \"imgui.h\"\n#endif\n\n#include <stdio.h>      // FILE*, sscanf\n#include <stdlib.h>     // NULL, malloc, free, qsort, atoi, atof\n#include <math.h>       // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf\n#include <limits.h>     // INT_MIN, INT_MAX\n\n// Enable SSE intrinsics if available\n#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE)\n#define IMGUI_ENABLE_SSE\n#include <immintrin.h>\n#endif\n\n// Visual Studio warnings\n#ifdef _MSC_VER\n#pragma warning (push)\n#pragma warning (disable: 4251)     // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport)\n#pragma warning (disable: 26812)    // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)\n#pragma warning (disable: 26495)    // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).\n#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later\n#pragma warning (disable: 5054)     // operator '|': deprecated between enumerations of different types\n#endif\n#endif\n\n// Clang/GCC warnings with -Weverything\n#if defined(__clang__)\n#pragma clang diagnostic push\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wfloat-equal\"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned()\n#pragma clang diagnostic ignored \"-Wunused-function\"                // for stb_textedit.h\n#pragma clang diagnostic ignored \"-Wmissing-prototypes\"             // for stb_textedit.h\n#pragma clang diagnostic ignored \"-Wold-style-cast\"\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"\n#pragma clang diagnostic ignored \"-Wimplicit-int-float-conversion\"  // warning: implicit conversion from 'xxx' to 'float' may lose precision\n#pragma clang diagnostic ignored \"-Wmissing-noreturn\"               // warning: function 'xxx' could be declared with attribute 'noreturn'\n#elif defined(__GNUC__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wpragmas\"              // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"      // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#endif\n\n// In 1.89.4, we moved the implementation of \"courtesy maths operators\" from imgui_internal.h in imgui.h\n// As they are frequently requested, we do not want to encourage to many people using imgui_internal.h\n#if defined(IMGUI_DEFINE_MATH_OPERATORS) && !defined(IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED)\n#error Please '#define IMGUI_DEFINE_MATH_OPERATORS' _BEFORE_ including imgui.h!\n#endif\n\n// Legacy defines\n#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS            // Renamed in 1.74\n#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS\n#endif\n#ifdef IMGUI_DISABLE_MATH_FUNCTIONS                     // Renamed in 1.74\n#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS\n#endif\n\n// Enable stb_truetype by default unless FreeType is enabled.\n// You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together.\n#ifndef IMGUI_ENABLE_FREETYPE\n#define IMGUI_ENABLE_STB_TRUETYPE\n#endif\n\n//-----------------------------------------------------------------------------\n// [SECTION] Forward declarations\n//-----------------------------------------------------------------------------\n\nstruct ImBitVector;                 // Store 1-bit per value\nstruct ImRect;                      // An axis-aligned rectangle (2 points)\nstruct ImDrawDataBuilder;           // Helper to build a ImDrawData instance\nstruct ImDrawListSharedData;        // Data shared between all ImDrawList instances\nstruct ImGuiColorMod;               // Stacked color modifier, backup of modified data so we can restore it\nstruct ImGuiContext;                // Main Dear ImGui context\nstruct ImGuiContextHook;            // Hook for extensions like ImGuiTestEngine\nstruct ImGuiDataVarInfo;            // Variable information (e.g. to avoid style variables from an enum)\nstruct ImGuiDataTypeInfo;           // Type information associated to a ImGuiDataType enum\nstruct ImGuiGroupData;              // Stacked storage data for BeginGroup()/EndGroup()\nstruct ImGuiInputTextState;         // Internal state of the currently focused/edited text input box\nstruct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id\nstruct ImGuiLastItemData;           // Status storage for last submitted items\nstruct ImGuiLocEntry;               // A localization entry.\nstruct ImGuiMenuColumns;            // Simple column measurement, currently used for MenuItem() only\nstruct ImGuiNavItemData;            // Result of a gamepad/keyboard directional navigation move query result\nstruct ImGuiNavTreeNodeData;        // Temporary storage for last TreeNode() being a Left arrow landing candidate.\nstruct ImGuiMetricsConfig;          // Storage for ShowMetricsWindow() and DebugNodeXXX() functions\nstruct ImGuiNextWindowData;         // Storage for SetNextWindow** functions\nstruct ImGuiNextItemData;           // Storage for SetNextItem** functions\nstruct ImGuiOldColumnData;          // Storage data for a single column for legacy Columns() api\nstruct ImGuiOldColumns;             // Storage data for a columns set for legacy Columns() api\nstruct ImGuiPopupData;              // Storage for current popup stack\nstruct ImGuiSettingsHandler;        // Storage for one type registered in the .ini file\nstruct ImGuiStackSizes;             // Storage of stack sizes for debugging/asserting\nstruct ImGuiStyleMod;               // Stacked style modifier, backup of modified data so we can restore it\nstruct ImGuiTabBar;                 // Storage for a tab bar\nstruct ImGuiTabItem;                // Storage for a tab item (within a tab bar)\nstruct ImGuiTable;                  // Storage for a table\nstruct ImGuiTableColumn;            // Storage for one column of a table\nstruct ImGuiTableInstanceData;      // Storage for one instance of a same table\nstruct ImGuiTableTempData;          // Temporary storage for one table (one per table in the stack), shared between tables.\nstruct ImGuiTableSettings;          // Storage for a table .ini settings\nstruct ImGuiTableColumnsSettings;   // Storage for a column .ini settings\nstruct ImGuiWindow;                 // Storage for one window\nstruct ImGuiWindowTempData;         // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window)\nstruct ImGuiWindowSettings;         // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)\n\n// Enumerations\n// Use your programming IDE \"Go to definition\" facility on the names of the center columns to find the actual flags/enum lists.\nenum ImGuiLocKey : int;                 // -> enum ImGuiLocKey              // Enum: a localization entry for translation.\ntypedef int ImGuiLayoutType;            // -> enum ImGuiLayoutType_         // Enum: Horizontal or vertical\n\n// Flags\ntypedef int ImGuiActivateFlags;         // -> enum ImGuiActivateFlags_      // Flags: for navigation/focus function (will be for ActivateItem() later)\ntypedef int ImGuiDebugLogFlags;         // -> enum ImGuiDebugLogFlags_      // Flags: for ShowDebugLogWindow(), g.DebugLogFlags\ntypedef int ImGuiFocusRequestFlags;     // -> enum ImGuiFocusRequestFlags_  // Flags: for FocusWindow();\ntypedef int ImGuiInputFlags;            // -> enum ImGuiInputFlags_         // Flags: for IsKeyPressed(), IsMouseClicked(), SetKeyOwner(), SetItemKeyOwner() etc.\ntypedef int ImGuiItemFlags;             // -> enum ImGuiItemFlags_          // Flags: for PushItemFlag(), g.LastItemData.InFlags\ntypedef int ImGuiItemStatusFlags;       // -> enum ImGuiItemStatusFlags_    // Flags: for g.LastItemData.StatusFlags\ntypedef int ImGuiOldColumnFlags;        // -> enum ImGuiOldColumnFlags_     // Flags: for BeginColumns()\ntypedef int ImGuiNavHighlightFlags;     // -> enum ImGuiNavHighlightFlags_  // Flags: for RenderNavHighlight()\ntypedef int ImGuiNavMoveFlags;          // -> enum ImGuiNavMoveFlags_       // Flags: for navigation requests\ntypedef int ImGuiNextItemDataFlags;     // -> enum ImGuiNextItemDataFlags_  // Flags: for SetNextItemXXX() functions\ntypedef int ImGuiNextWindowDataFlags;   // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions\ntypedef int ImGuiScrollFlags;           // -> enum ImGuiScrollFlags_        // Flags: for ScrollToItem() and navigation requests\ntypedef int ImGuiSeparatorFlags;        // -> enum ImGuiSeparatorFlags_     // Flags: for SeparatorEx()\ntypedef int ImGuiTextFlags;             // -> enum ImGuiTextFlags_          // Flags: for TextEx()\ntypedef int ImGuiTooltipFlags;          // -> enum ImGuiTooltipFlags_       // Flags: for BeginTooltipEx()\n\ntypedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...);\n\n//-----------------------------------------------------------------------------\n// [SECTION] Context pointer\n// See implementation of this variable in imgui.cpp for comments and details.\n//-----------------------------------------------------------------------------\n\n#ifndef GImGui\nextern IMGUI_API ImGuiContext* GImGui;  // Current implicit context pointer\n#endif\n\n//-------------------------------------------------------------------------\n// [SECTION] STB libraries includes\n//-------------------------------------------------------------------------\n\nnamespace ImStb\n{\n#undef STB_TEXTEDIT_STRING\n#undef STB_TEXTEDIT_CHARTYPE\n#define STB_TEXTEDIT_STRING             ImGuiInputTextState\n#define STB_TEXTEDIT_CHARTYPE           ImWchar\n#define STB_TEXTEDIT_GETWIDTH_NEWLINE   (-1.0f)\n#define STB_TEXTEDIT_UNDOSTATECOUNT     99\n#define STB_TEXTEDIT_UNDOCHARCOUNT      999\n#include \"imstb_textedit.h\"\n} // namespace ImStb\n\n//-----------------------------------------------------------------------------\n// [SECTION] Macros\n//-----------------------------------------------------------------------------\n\n// Debug Printing Into TTY\n// (since IMGUI_VERSION_NUM >= 18729: IMGUI_DEBUG_LOG was reworked into IMGUI_DEBUG_PRINTF (and removed framecount from it). If you were using a #define IMGUI_DEBUG_LOG please rename)\n#ifndef IMGUI_DEBUG_PRINTF\n#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS\n#define IMGUI_DEBUG_PRINTF(_FMT,...)    printf(_FMT, __VA_ARGS__)\n#else\n#define IMGUI_DEBUG_PRINTF(_FMT,...)    ((void)0)\n#endif\n#endif\n\n// Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam.\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n#define IMGUI_DEBUG_LOG(...)            ImGui::DebugLog(__VA_ARGS__)\n#else\n#define IMGUI_DEBUG_LOG(...)            ((void)0)\n#endif\n#define IMGUI_DEBUG_LOG_ACTIVEID(...)   do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_FOCUS(...)      do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus)    IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_POPUP(...)      do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup)    IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_NAV(...)        do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav)      IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_SELECTION(...)  do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_CLIPPER(...)    do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper)  IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n#define IMGUI_DEBUG_LOG_IO(...)         do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO)       IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)\n\n// Static Asserts\n#define IM_STATIC_ASSERT(_COND)         static_assert(_COND, \"\")\n\n// \"Paranoid\" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much.\n// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code.\n//#define IMGUI_DEBUG_PARANOID\n#ifdef IMGUI_DEBUG_PARANOID\n#define IM_ASSERT_PARANOID(_EXPR)       IM_ASSERT(_EXPR)\n#else\n#define IM_ASSERT_PARANOID(_EXPR)\n#endif\n\n// Error handling\n// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults.\n#ifndef IM_ASSERT_USER_ERROR\n#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG)   // Recoverable User Error\n#endif\n\n// Misc Macros\n#define IM_PI                           3.14159265358979323846f\n#ifdef _WIN32\n#define IM_NEWLINE                      \"\\r\\n\"   // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!)\n#else\n#define IM_NEWLINE                      \"\\n\"\n#endif\n#ifndef IM_TABSIZE                      // Until we move this to runtime and/or add proper tab support, at least allow users to compile-time override\n#define IM_TABSIZE                      (4)\n#endif\n#define IM_MEMALIGN(_OFF,_ALIGN)        (((_OFF) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1))           // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8\n#define IM_F32_TO_INT8_UNBOUND(_VAL)    ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f)))   // Unsaturated, for display purpose\n#define IM_F32_TO_INT8_SAT(_VAL)        ((int)(ImSaturate(_VAL) * 255.0f + 0.5f))               // Saturated, always output 0..255\n#define IM_FLOOR(_VAL)                  ((float)(int)(_VAL))                                    // ImFloor() is not inlined in MSVC debug builds\n#define IM_ROUND(_VAL)                  ((float)(int)((_VAL) + 0.5f))                           //\n#define IM_STRINGIFY_HELPER(_X)         #_X\n#define IM_STRINGIFY(_X)                IM_STRINGIFY_HELPER(_X)                                 // Preprocessor idiom to stringify e.g. an integer.\n\n// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall\n#ifdef _MSC_VER\n#define IMGUI_CDECL __cdecl\n#else\n#define IMGUI_CDECL\n#endif\n\n// Warnings\n#if defined(_MSC_VER) && !defined(__clang__)\n#define IM_MSVC_WARNING_SUPPRESS(XXXX)  __pragma(warning(suppress: XXXX))\n#else\n#define IM_MSVC_WARNING_SUPPRESS(XXXX)\n#endif\n\n// Debug Tools\n// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item.\n// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference.\n#ifndef IM_DEBUG_BREAK\n#if defined (_MSC_VER)\n#define IM_DEBUG_BREAK()    __debugbreak()\n#elif defined(__clang__)\n#define IM_DEBUG_BREAK()    __builtin_debugtrap()\n#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))\n#define IM_DEBUG_BREAK()    __asm__ volatile(\"int $0x03\")\n#elif defined(__GNUC__) && defined(__thumb__)\n#define IM_DEBUG_BREAK()    __asm__ volatile(\".inst 0xde01\")\n#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__)\n#define IM_DEBUG_BREAK()    __asm__ volatile(\".inst 0xe7f001f0\");\n#else\n#define IM_DEBUG_BREAK()    IM_ASSERT(0)    // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger!\n#endif\n#endif // #ifndef IM_DEBUG_BREAK\n\n//-----------------------------------------------------------------------------\n// [SECTION] Generic helpers\n// Note that the ImXXX helpers functions are lower-level than ImGui functions.\n// ImGui functions or the ImGui context are never called/used from other ImXXX functions.\n//-----------------------------------------------------------------------------\n// - Helpers: Hashing\n// - Helpers: Sorting\n// - Helpers: Bit manipulation\n// - Helpers: String\n// - Helpers: Formatting\n// - Helpers: UTF-8 <> wchar conversions\n// - Helpers: ImVec2/ImVec4 operators\n// - Helpers: Maths\n// - Helpers: Geometry\n// - Helper: ImVec1\n// - Helper: ImVec2ih\n// - Helper: ImRect\n// - Helper: ImBitArray\n// - Helper: ImBitVector\n// - Helper: ImSpan<>, ImSpanAllocator<>\n// - Helper: ImPool<>\n// - Helper: ImChunkStream<>\n// - Helper: ImGuiTextIndex\n//-----------------------------------------------------------------------------\n\n// Helpers: Hashing\nIMGUI_API ImGuiID       ImHashData(const void* data, size_t data_size, ImGuiID seed = 0);\nIMGUI_API ImGuiID       ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0);\n\n// Helpers: Sorting\n#ifndef ImQsort\nstatic inline void      ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL* compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); }\n#endif\n\n// Helpers: Color Blending\nIMGUI_API ImU32         ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);\n\n// Helpers: Bit manipulation\nstatic inline bool      ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }\nstatic inline bool      ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }\nstatic inline int       ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }\n\n// Helpers: String\nIMGUI_API int           ImStricmp(const char* str1, const char* str2);\nIMGUI_API int           ImStrnicmp(const char* str1, const char* str2, size_t count);\nIMGUI_API void          ImStrncpy(char* dst, const char* src, size_t count);\nIMGUI_API char* ImStrdup(const char* str);\nIMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str);\nIMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c);\nIMGUI_API int           ImStrlenW(const ImWchar* str);\nIMGUI_API const char* ImStreolRange(const char* str, const char* str_end);                // End end-of-line\nIMGUI_API const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin);   // Find beginning-of-line\nIMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);\nIMGUI_API void          ImStrTrimBlanks(char* str);\nIMGUI_API const char* ImStrSkipBlank(const char* str);\nIM_MSVC_RUNTIME_CHECKS_OFF\nstatic inline char      ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }\nstatic inline bool      ImCharIsBlankA(char c) { return c == ' ' || c == '\\t'; }\nstatic inline bool      ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\\t' || c == 0x3000; }\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n// Helpers: Formatting\nIMGUI_API int           ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3);\nIMGUI_API int           ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);\nIMGUI_API void          ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...) IM_FMTARGS(3);\nIMGUI_API void          ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) IM_FMTLIST(3);\nIMGUI_API const char* ImParseFormatFindStart(const char* format);\nIMGUI_API const char* ImParseFormatFindEnd(const char* format);\nIMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);\nIMGUI_API void          ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size);\nIMGUI_API const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size);\nIMGUI_API int           ImParseFormatPrecision(const char* format, int default_value);\n\n// Helpers: UTF-8 <> wchar conversions\nIMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c);                                                      // return out_buf\nIMGUI_API int           ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end);   // return output UTF-8 bytes count\nIMGUI_API int           ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end);               // read one character. return input UTF-8 bytes count\nIMGUI_API int           ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL);   // return input UTF-8 bytes count\nIMGUI_API int           ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end);                                 // return number of UTF-8 code-points (NOT bytes count)\nIMGUI_API int           ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end);                             // return number of bytes to express one char in UTF-8\nIMGUI_API int           ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end);                        // return number of bytes to express string in UTF-8\n\n// Helpers: File System\n#ifdef IMGUI_DISABLE_FILE_FUNCTIONS\n#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS\ntypedef void* ImFileHandle;\nstatic inline ImFileHandle  ImFileOpen(const char*, const char*) { return NULL; }\nstatic inline bool          ImFileClose(ImFileHandle) { return false; }\nstatic inline ImU64         ImFileGetSize(ImFileHandle) { return (ImU64)-1; }\nstatic inline ImU64         ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; }\nstatic inline ImU64         ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; }\n#endif\n#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS\ntypedef FILE* ImFileHandle;\nIMGUI_API ImFileHandle      ImFileOpen(const char* filename, const char* mode);\nIMGUI_API bool              ImFileClose(ImFileHandle file);\nIMGUI_API ImU64             ImFileGetSize(ImFileHandle file);\nIMGUI_API ImU64             ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file);\nIMGUI_API ImU64             ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file);\n#else\n#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions\n#endif\nIMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0);\n\n// Helpers: Maths\nIM_MSVC_RUNTIME_CHECKS_OFF\n// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy)\n#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS\n#define ImFabs(X)           fabsf(X)\n#define ImSqrt(X)           sqrtf(X)\n#define ImFmod(X, Y)        fmodf((X), (Y))\n#define ImCos(X)            cosf(X)\n#define ImSin(X)            sinf(X)\n#define ImAcos(X)           acosf(X)\n#define ImAtan2(Y, X)       atan2f((Y), (X))\n#define ImAtof(STR)         atof(STR)\n//#define ImFloorStd(X)     floorf(X)           // We use our own, see ImFloor() and ImFloorSigned()\n#define ImCeil(X)           ceilf(X)\nstatic inline float  ImPow(float x, float y) { return powf(x, y); }          // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision\nstatic inline double ImPow(double x, double y) { return pow(x, y); }\nstatic inline float  ImLog(float x) { return logf(x); }             // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision\nstatic inline double ImLog(double x) { return log(x); }\nstatic inline int    ImAbs(int x) { return x < 0 ? -x : x; }\nstatic inline float  ImAbs(float x) { return fabsf(x); }\nstatic inline double ImAbs(double x) { return fabs(x); }\nstatic inline float  ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument\nstatic inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; }\n#ifdef IMGUI_ENABLE_SSE\nstatic inline float  ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }\n#else\nstatic inline float  ImRsqrt(float x) { return 1.0f / sqrtf(x); }\n#endif\nstatic inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }\n#endif\n// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double\n// (Exceptionally using templates here but we could also redefine them for those types)\ntemplate<typename T> static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }\ntemplate<typename T> static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }\ntemplate<typename T> static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }\ntemplate<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }\ntemplate<typename T> static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }\ntemplate<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }\ntemplate<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }\n// - Misc maths helpers\nstatic inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }\nstatic inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }\nstatic inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }\nstatic inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }\nstatic inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }\nstatic inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }\nstatic inline float  ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }\nstatic inline float  ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); }\nstatic inline float  ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); }\nstatic inline float  ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; }\nstatic inline float  ImFloor(float f) { return (float)(int)(f); }\nstatic inline float  ImFloorSigned(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf()\nstatic inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }\nstatic inline ImVec2 ImFloorSigned(const ImVec2& v) { return ImVec2(ImFloorSigned(v.x), ImFloorSigned(v.y)); }\nstatic inline int    ImModPositive(int a, int b) { return (a + b) % b; }\nstatic inline float  ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }\nstatic inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }\nstatic inline float  ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }\nstatic inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }\nstatic inline bool   ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }\nstatic inline float  ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n// Helpers: Geometry\nIMGUI_API ImVec2     ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t);\nIMGUI_API ImVec2     ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments);       // For curves with explicit number of segments\nIMGUI_API ImVec2     ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol\nIMGUI_API ImVec2     ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t);\nIMGUI_API ImVec2     ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);\nIMGUI_API bool       ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);\nIMGUI_API ImVec2     ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);\nIMGUI_API void       ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);\ninline float         ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; }\n\n// Helper: ImVec1 (1D vector)\n// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)\nIM_MSVC_RUNTIME_CHECKS_OFF\nstruct ImVec1\n{\n\tfloat   x;\n\tconstexpr ImVec1() : x(0.0f) { }\n\tconstexpr ImVec1(float _x) : x(_x) { }\n};\n\n// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage)\nstruct ImVec2ih\n{\n\tshort   x, y;\n\tconstexpr ImVec2ih() : x(0), y(0) {}\n\tconstexpr ImVec2ih(short _x, short _y) : x(_x), y(_y) {}\n\tconstexpr explicit ImVec2ih(const ImVec2& rhs) : x((short)rhs.x), y((short)rhs.y) {}\n};\n\n// Helper: ImRect (2D axis aligned bounding-box)\n// NB: we can't rely on ImVec2 math operators being available here!\nstruct IMGUI_API ImRect\n{\n\tImVec2      Min;    // Upper-left\n\tImVec2      Max;    // Lower-right\n\n\tconstexpr ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {}\n\tconstexpr ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {}\n\tconstexpr ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {}\n\tconstexpr ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {}\n\n\tImVec2      GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); }\n\tImVec2      GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); }\n\tfloat       GetWidth() const { return Max.x - Min.x; }\n\tfloat       GetHeight() const { return Max.y - Min.y; }\n\tfloat       GetArea() const { return (Max.x - Min.x) * (Max.y - Min.y); }\n\tImVec2      GetTL() const { return Min; }                   // Top-left\n\tImVec2      GetTR() const { return ImVec2(Max.x, Min.y); }  // Top-right\n\tImVec2      GetBL() const { return ImVec2(Min.x, Max.y); }  // Bottom-left\n\tImVec2      GetBR() const { return Max; }                   // Bottom-right\n\tbool        Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; }\n\tbool        Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; }\n\tbool        Overlaps(const ImRect& r) const { return r.Min.y <  Max.y && r.Max.y >  Min.y && r.Min.x <  Max.x && r.Max.x >  Min.x; }\n\tvoid        Add(const ImVec2& p) { if (Min.x > p.x)     Min.x = p.x;     if (Min.y > p.y)     Min.y = p.y;     if (Max.x < p.x)     Max.x = p.x;     if (Max.y < p.y)     Max.y = p.y; }\n\tvoid        Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; }\n\tvoid        Expand(const float amount) { Min.x -= amount;   Min.y -= amount;   Max.x += amount;   Max.y += amount; }\n\tvoid        Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; }\n\tvoid        Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; }\n\tvoid        TranslateX(float dx) { Min.x += dx; Max.x += dx; }\n\tvoid        TranslateY(float dy) { Min.y += dy; Max.y += dy; }\n\tvoid        ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); }                   // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display.\n\tvoid        ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped.\n\tvoid        Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); }\n\tbool        IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }\n\tImVec4      ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); }\n};\n\n// Helper: ImBitArray\n#define         IM_BITARRAY_TESTBIT(_ARRAY, _N)                 ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly!\n#define         IM_BITARRAY_CLEARBIT(_ARRAY, _N)                ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31))))    // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly!\ninline size_t   ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; }\ninline void     ImBitArrayClearAllBits(ImU32* arr, int bitcount) { memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); }\ninline bool     ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; }\ninline void     ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; }\ninline void     ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; }\ninline void     ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on range [n..n2)\n{\n\tn2--;\n\twhile (n <= n2)\n\t{\n\t\tint a_mod = (n & 31);\n\t\tint b_mod = (n2 > (n | 31) ? 31 : (n2 & 31)) + 1;\n\t\tImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1);\n\t\tarr[n >> 5] |= mask;\n\t\tn = (n + 32) & ~31;\n\t}\n}\n\ntypedef ImU32* ImBitArrayPtr; // Name for use in structs\n\n// Helper: ImBitArray class (wrapper over ImBitArray functions)\n// Store 1-bit per value.\ntemplate<int BITCOUNT, int OFFSET = 0>\nstruct ImBitArray\n{\n\tImU32           Storage[(BITCOUNT + 31) >> 5];\n\tImBitArray() { ClearAllBits(); }\n\tvoid            ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }\n\tvoid            SetAllBits() { memset(Storage, 255, sizeof(Storage)); }\n\tbool            TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }\n\tvoid            SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); }\n\tvoid            ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); }\n\tvoid            SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2)\n\tbool            operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }\n};\n\n// Helper: ImBitVector\n// Store 1-bit per value.\nstruct IMGUI_API ImBitVector\n{\n\tImVector<ImU32> Storage;\n\tvoid            Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }\n\tvoid            Clear() { Storage.clear(); }\n\tbool            TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); }\n\tvoid            SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }\n\tvoid            ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }\n};\nIM_MSVC_RUNTIME_CHECKS_RESTORE\n\n// Helper: ImSpan<>\n// Pointing to a span of data we don't own.\ntemplate<typename T>\nstruct ImSpan\n{\n\tT* Data;\n\tT* DataEnd;\n\n\t// Constructors, destructor\n\tinline ImSpan() { Data = DataEnd = NULL; }\n\tinline ImSpan(T* data, int size) { Data = data; DataEnd = data + size; }\n\tinline ImSpan(T* data, T* data_end) { Data = data; DataEnd = data_end; }\n\n\tinline void         set(T* data, int size) { Data = data; DataEnd = data + size; }\n\tinline void         set(T* data, T* data_end) { Data = data; DataEnd = data_end; }\n\tinline int          size() const { return (int)(ptrdiff_t)(DataEnd - Data); }\n\tinline int          size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); }\n\tinline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; }\n\tinline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; }\n\n\tinline T* begin() { return Data; }\n\tinline const T* begin() const { return Data; }\n\tinline T* end() { return DataEnd; }\n\tinline const T* end() const { return DataEnd; }\n\n\t// Utilities\n\tinline int  index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; }\n};\n\n// Helper: ImSpanAllocator<>\n// Facilitate storing multiple chunks into a single large block (the \"arena\")\n// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges.\ntemplate<int CHUNKS>\nstruct ImSpanAllocator\n{\n\tchar* BasePtr;\n\tint     CurrOff;\n\tint     CurrIdx;\n\tint     Offsets[CHUNKS];\n\tint     Sizes[CHUNKS];\n\n\tImSpanAllocator() { memset(this, 0, sizeof(*this)); }\n\tinline void  Reserve(int n, size_t sz, int a = 4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; }\n\tinline int   GetArenaSizeInBytes() { return CurrOff; }\n\tinline void  SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; }\n\tinline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); }\n\tinline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); }\n\ttemplate<typename T>\n\tinline void  GetSpan(int n, ImSpan<T>* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); }\n};\n\n// Helper: ImPool<>\n// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,\n// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.\ntypedef int ImPoolIdx;\ntemplate<typename T>\nstruct ImPool\n{\n\tImVector<T>     Buf;        // Contiguous data\n\tImGuiStorage    Map;        // ID->Index\n\tImPoolIdx       FreeIdx;    // Next free idx to use\n\tImPoolIdx       AliveCount; // Number of active/alive items (for display purpose)\n\n\tImPool() { FreeIdx = AliveCount = 0; }\n\t~ImPool() { Clear(); }\n\tT* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; }\n\tT* GetByIndex(ImPoolIdx n) { return &Buf[n]; }\n\tImPoolIdx   GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); }\n\tT* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); }\n\tbool        Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); }\n\tvoid        Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = AliveCount = 0; }\n\tT* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); AliveCount++; return &Buf[idx]; }\n\tvoid        Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }\n\tvoid        Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); AliveCount--; }\n\tvoid        Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); }\n\n\t// To iterate a ImPool: for (int n = 0; n < pool.GetMapSize(); n++) if (T* t = pool.TryGetMapData(n)) { ... }\n\t// Can be avoided if you know .Remove() has never been called on the pool, or AliveCount == GetMapSize()\n\tint         GetAliveCount() const { return AliveCount; }      // Number of active/alive items in the pool (for display purpose)\n\tint         GetBufSize() const { return Buf.Size; }\n\tint         GetMapSize() const { return Map.Data.Size; }   // It is the map we need iterate to find valid items, since we don't have \"alive\" storage anywhere\n\tT* TryGetMapData(ImPoolIdx n) { int idx = Map.Data[n].val_i; if (idx == -1) return NULL; return GetByIndex(idx); }\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tint         GetSize() { return GetMapSize(); } // For ImPlot: should use GetMapSize() from (IMGUI_VERSION_NUM >= 18304)\n#endif\n};\n\n// Helper: ImChunkStream<>\n// Build and iterate a contiguous stream of variable-sized structures.\n// This is used by Settings to store persistent data while reducing allocation count.\n// We store the chunk size first, and align the final size on 4 bytes boundaries.\n// The tedious/zealous amount of casting is to avoid -Wcast-align warnings.\ntemplate<typename T>\nstruct ImChunkStream\n{\n\tImVector<char>  Buf;\n\n\tvoid    clear() { Buf.clear(); }\n\tbool    empty() const { return Buf.Size == 0; }\n\tint     size() const { return Buf.Size; }\n\tT* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }\n\tT* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); }\n\tT* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; }\n\tint     chunk_size(const T* p) { return ((const int*)p)[-1]; }\n\tT* end() { return (T*)(void*)(Buf.Data + Buf.Size); }\n\tint     offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; }\n\tT* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); }\n\tvoid    swap(ImChunkStream<T>& rhs) { rhs.Buf.swap(Buf); }\n};\n\n// Helper: ImGuiTextIndex<>\n// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.\nstruct ImGuiTextIndex\n{\n\tImVector<int>   LineOffsets;\n\tint             EndOffset = 0;                          // Because we don't own text buffer we need to maintain EndOffset (may bake in LineOffsets?)\n\n\tvoid            clear() { LineOffsets.clear(); EndOffset = 0; }\n\tint             size() { return LineOffsets.Size; }\n\tconst char* get_line_begin(const char* base, int n) { return base + LineOffsets[n]; }\n\tconst char* get_line_end(const char* base, int n) { return base + (n + 1 < LineOffsets.Size ? (LineOffsets[n + 1] - 1) : EndOffset); }\n\tvoid            append(const char* base, int old_size, int new_size);\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImDrawList support\n//-----------------------------------------------------------------------------\n\n// ImDrawList: Helper function to calculate a circle's segment count given its radius and a \"maximum error\" value.\n// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693\n// Number of segments (N) is calculated using equation:\n//   N = ceil ( pi / acos(1 - error / r) )     where r > 0, error <= r\n// Our equation is significantly simpler that one in the post thanks for choosing segment that is\n// perpendicular to X axis. Follow steps in the article from this starting condition and you will\n// will get this result.\n//\n// Rendering circles with an odd number of segments, while mathematically correct will produce\n// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.)\n#define IM_ROUNDUP_TO_EVEN(_V)                                  ((((_V) + 1) / 2) * 2)\n#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN                     4\n#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX                     512\n#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR)    ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX)\n\n// Raw equation from IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC rewritten for 'r' and 'error'.\n#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR)    ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))))\n#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD)     ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD))\n\n// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle.\n#ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE\n#define IM_DRAWLIST_ARCFAST_TABLE_SIZE                          48 // Number of samples in lookup table.\n#endif\n#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX                          IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle.\n\n// Data shared between all ImDrawList instances\n// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure.\nstruct IMGUI_API ImDrawListSharedData\n{\n\tImVec2          TexUvWhitePixel;            // UV of white pixel in the atlas\n\tImFont* Font;                       // Current/default font (optional, for simplified AddText overload)\n\tfloat           FontSize;                   // Current/default font size (optional, for simplified AddText overload)\n\tfloat           CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo()\n\tfloat           CircleSegmentMaxError;      // Number of circle segments to use per pixel of radius for AddCircle() etc\n\tImVec4          ClipRectFullscreen;         // Value for PushClipRectFullscreen()\n\tImDrawListFlags InitialFlags;               // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)\n\n\t// [Internal] Temp write buffer\n\tImVector<ImVec2> TempBuffer;\n\n\t// [Internal] Lookup tables\n\tImVec2          ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle.\n\tfloat           ArcFastRadiusCutoff;                        // Cutoff radius after which arc drawing will fallback to slower PathArcTo()\n\tImU8            CircleSegmentCounts[64];    // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead)\n\tconst ImVec4* TexUvLines;                 // UV of anti-aliased lines in the atlas\n\n\tImDrawListSharedData();\n\tvoid SetCircleTessellationMaxError(float max_error);\n};\n\nstruct ImDrawDataBuilder\n{\n\tImVector<ImDrawList*>* Layers[2];      // Pointers to global layers for: regular, tooltip. LayersP[0] is owned by DrawData.\n\tImVector<ImDrawList*>   LayerData1;\n\n\tImDrawDataBuilder() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Widgets support: flags, enums, data structures\n//-----------------------------------------------------------------------------\n\n// Flags used by upcoming items\n// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags.\n// - output: stored in g.LastItemData.InFlags\n// Current window shared by all windows.\n// This is going to be exposed in imgui.h when stabilized enough.\nenum ImGuiItemFlags_\n{\n\t// Controlled by user\n\tImGuiItemFlags_None = 0,\n\tImGuiItemFlags_NoTabStop = 1 << 0,  // false     // Disable keyboard tabbing. This is a \"lighter\" version of ImGuiItemFlags_NoNav.\n\tImGuiItemFlags_ButtonRepeat = 1 << 1,  // false     // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.\n\tImGuiItemFlags_Disabled = 1 << 2,  // false     // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211\n\tImGuiItemFlags_NoNav = 1 << 3,  // false     // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls)\n\tImGuiItemFlags_NoNavDefaultFocus = 1 << 4,  // false     // Disable item being a candidate for default focus (e.g. used by title bar items)\n\tImGuiItemFlags_SelectableDontClosePopup = 1 << 5,  // false     // Disable MenuItem/Selectable() automatically closing their popup window\n\tImGuiItemFlags_MixedValue = 1 << 6,  // false     // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)\n\tImGuiItemFlags_ReadOnly = 1 << 7,  // false     // [ALPHA] Allow hovering interactions but underlying value is not changed.\n\tImGuiItemFlags_NoWindowHoverableCheck = 1 << 8,  // false     // Disable hoverable check in ItemHoverable()\n\tImGuiItemFlags_AllowOverlap = 1 << 9,  // false     // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.\n\n\t// Controlled by widget code\n\tImGuiItemFlags_Inputable = 1 << 10, // false     // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.\n};\n\n// Status flags for an already submitted item\n// - output: stored in g.LastItemData.StatusFlags\nenum ImGuiItemStatusFlags_\n{\n\tImGuiItemStatusFlags_None = 0,\n\tImGuiItemStatusFlags_HoveredRect = 1 << 0,   // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test)\n\tImGuiItemStatusFlags_HasDisplayRect = 1 << 1,   // g.LastItemData.DisplayRect is valid\n\tImGuiItemStatusFlags_Edited = 1 << 2,   // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)\n\tImGuiItemStatusFlags_ToggledSelection = 1 << 3,   // Set when Selectable(), TreeNode() reports toggling a selection. We can't report \"Selected\", only state changes, in order to easily handle clipping with less issues.\n\tImGuiItemStatusFlags_ToggledOpen = 1 << 4,   // Set when TreeNode() reports toggling their open state.\n\tImGuiItemStatusFlags_HasDeactivated = 1 << 5,   // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.\n\tImGuiItemStatusFlags_Deactivated = 1 << 6,   // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.\n\tImGuiItemStatusFlags_HoveredWindow = 1 << 7,   // Override the HoveredWindow test to allow cross-window hover testing.\n\tImGuiItemStatusFlags_FocusedByTabbing = 1 << 8,   // Set when the Focusable item just got focused by Tabbing (FIXME: to be removed soon)\n\tImGuiItemStatusFlags_Visible = 1 << 9,   // [WIP] Set when item is overlapping the current clipping rectangle (Used internally. Please don't use yet: API/system will change as we refactor Itemadd()).\n\n\t// Additional status + semantic for ImGuiTestEngine\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\tImGuiItemStatusFlags_Openable = 1 << 20,  // Item is an openable (e.g. TreeNode)\n\tImGuiItemStatusFlags_Opened = 1 << 21,  // Opened status\n\tImGuiItemStatusFlags_Checkable = 1 << 22,  // Item is a checkable (e.g. CheckBox, MenuItem)\n\tImGuiItemStatusFlags_Checked = 1 << 23,  // Checked status\n\tImGuiItemStatusFlags_Inputable = 1 << 24,  // Item is a text-inputable (e.g. InputText, SliderXXX, DragXXX)\n#endif\n};\n\n// Extend ImGuiHoveredFlags_\nenum ImGuiHoveredFlagsPrivate_\n{\n\tImGuiHoveredFlags_DelayMask_ = ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay,\n\tImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary,\n\tImGuiHoveredFlags_AllowedMaskForIsItemHovered = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayMask_,\n};\n\n// Extend ImGuiInputTextFlags_\nenum ImGuiInputTextFlagsPrivate_\n{\n\t// [Internal]\n\tImGuiInputTextFlags_Multiline = 1 << 26,  // For internal use by InputTextMultiline()\n\tImGuiInputTextFlags_NoMarkEdited = 1 << 27,  // For internal use by functions using InputText() before reformatting data\n\tImGuiInputTextFlags_MergedItem = 1 << 28,  // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.\n};\n\n// Extend ImGuiButtonFlags_\nenum ImGuiButtonFlagsPrivate_\n{\n\tImGuiButtonFlags_PressedOnClick = 1 << 4,   // return true on click (mouse down event)\n\tImGuiButtonFlags_PressedOnClickRelease = 1 << 5,   // [Default] return true on click + release on same item <-- this is what the majority of Button are using\n\tImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item\n\tImGuiButtonFlags_PressedOnRelease = 1 << 7,   // return true on release (default requires click+release)\n\tImGuiButtonFlags_PressedOnDoubleClick = 1 << 8,   // return true on double-click (default requires click+release)\n\tImGuiButtonFlags_PressedOnDragDropHold = 1 << 9,   // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)\n\tImGuiButtonFlags_Repeat = 1 << 10,  // hold to repeat\n\tImGuiButtonFlags_FlattenChildren = 1 << 11,  // allow interactions even if a child window is overlapping\n\tImGuiButtonFlags_AllowOverlap = 1 << 12,  // require previous frame HoveredId to either match id or be null before being usable.\n\tImGuiButtonFlags_DontClosePopups = 1 << 13,  // disable automatically closing parent popup on press // [UNUSED]\n\t//ImGuiButtonFlags_Disabled             = 1 << 14,  // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled\n\tImGuiButtonFlags_AlignTextBaseLine = 1 << 15,  // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine\n\tImGuiButtonFlags_NoKeyModifiers = 1 << 16,  // disable mouse interaction if a key modifier is held\n\tImGuiButtonFlags_NoHoldingActiveId = 1 << 17,  // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)\n\tImGuiButtonFlags_NoNavFocus = 1 << 18,  // don't override navigation focus when activated (FIXME: this is essentially used everytime an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.InFlags)\n\tImGuiButtonFlags_NoHoveredOnFocus = 1 << 19,  // don't report as hovered when nav focus is on this item\n\tImGuiButtonFlags_NoSetKeyOwner = 1 << 20,  // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!)\n\tImGuiButtonFlags_NoTestKeyOwner = 1 << 21,  // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!)\n\tImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold,\n\tImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease,\n};\n\n// Extend ImGuiComboFlags_\nenum ImGuiComboFlagsPrivate_\n{\n\tImGuiComboFlags_CustomPreview = 1 << 20,  // enable BeginComboPreview()\n};\n\n// Extend ImGuiSliderFlags_\nenum ImGuiSliderFlagsPrivate_\n{\n\tImGuiSliderFlags_Vertical = 1 << 20,  // Should this slider be orientated vertically?\n\tImGuiSliderFlags_ReadOnly = 1 << 21,  // Consider using g.NextItemData.ItemFlags |= ImGuiItemFlags_ReadOnly instead.\n};\n\n// Extend ImGuiSelectableFlags_\nenum ImGuiSelectableFlagsPrivate_\n{\n\t// NB: need to be in sync with last value of ImGuiSelectableFlags_\n\tImGuiSelectableFlags_NoHoldingActiveID = 1 << 20,\n\tImGuiSelectableFlags_SelectOnNav = 1 << 21,  // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API.\n\tImGuiSelectableFlags_SelectOnClick = 1 << 22,  // Override button behavior to react on Click (default is Click+Release)\n\tImGuiSelectableFlags_SelectOnRelease = 1 << 23,  // Override button behavior to react on Release (default is Click+Release)\n\tImGuiSelectableFlags_SpanAvailWidth = 1 << 24,  // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus)\n\tImGuiSelectableFlags_SetNavIdOnHover = 1 << 25,  // Set Nav/Focus ID on mouse hover (used by MenuItem)\n\tImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26,  // Disable padding each side with ItemSpacing * 0.5f\n\tImGuiSelectableFlags_NoSetKeyOwner = 1 << 27,  // Don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!)\n};\n\n// Extend ImGuiTreeNodeFlags_\nenum ImGuiTreeNodeFlagsPrivate_\n{\n\tImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20,\n\tImGuiTreeNodeFlags_UpsideDownArrow = 1 << 21,// (FIXME-WIP) Turn Down arrow into an Up arrow, but reversed trees (#6517)\n};\n\nenum ImGuiSeparatorFlags_\n{\n\tImGuiSeparatorFlags_None = 0,\n\tImGuiSeparatorFlags_Horizontal = 1 << 0,   // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar\n\tImGuiSeparatorFlags_Vertical = 1 << 1,\n\tImGuiSeparatorFlags_SpanAllColumns = 1 << 2,   // Make separator cover all columns of a legacy Columns() set.\n};\n\n// Flags for FocusWindow(). This is not called ImGuiFocusFlags to avoid confusion with public-facing ImGuiFocusedFlags.\n// FIXME: Once we finishing replacing more uses of GetTopMostPopupModal()+IsWindowWithinBeginStackOf()\n// and FindBlockingModal() with this, we may want to change the flag to be opt-out instead of opt-in.\nenum ImGuiFocusRequestFlags_\n{\n\tImGuiFocusRequestFlags_None = 0,\n\tImGuiFocusRequestFlags_RestoreFocusedChild = 1 << 0,   // Find last focused child (if any) and focus it instead.\n\tImGuiFocusRequestFlags_UnlessBelowModal = 1 << 1,   // Do not set focus if the window is below a modal.\n};\n\nenum ImGuiTextFlags_\n{\n\tImGuiTextFlags_None = 0,\n\tImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0,\n};\n\nenum ImGuiTooltipFlags_\n{\n\tImGuiTooltipFlags_None = 0,\n\tImGuiTooltipFlags_OverridePrevious = 1 << 1,   // Clear/ignore previously submitted tooltip (defaults to append)\n};\n\n// FIXME: this is in development, not exposed/functional as a generic feature yet.\n// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2\nenum ImGuiLayoutType_\n{\n\tImGuiLayoutType_Horizontal = 0,\n\tImGuiLayoutType_Vertical = 1\n};\n\nenum ImGuiLogType\n{\n\tImGuiLogType_None = 0,\n\tImGuiLogType_TTY,\n\tImGuiLogType_File,\n\tImGuiLogType_Buffer,\n\tImGuiLogType_Clipboard,\n};\n\n// X/Y enums are fixed to 0/1 so they may be used to index ImVec2\nenum ImGuiAxis\n{\n\tImGuiAxis_None = -1,\n\tImGuiAxis_X = 0,\n\tImGuiAxis_Y = 1\n};\n\nenum ImGuiPlotType\n{\n\tImGuiPlotType_Lines,\n\tImGuiPlotType_Histogram,\n};\n\nenum ImGuiPopupPositionPolicy\n{\n\tImGuiPopupPositionPolicy_Default,\n\tImGuiPopupPositionPolicy_ComboBox,\n\tImGuiPopupPositionPolicy_Tooltip,\n};\n\nstruct ImGuiDataVarInfo\n{\n\tImGuiDataType   Type;\n\tImU32           Count;      // 1+\n\tImU32           Offset;     // Offset in parent structure\n\tvoid* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }\n};\n\nstruct ImGuiDataTypeTempStorage\n{\n\tImU8        Data[8];        // Can fit any data up to ImGuiDataType_COUNT\n};\n\n// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().\nstruct ImGuiDataTypeInfo\n{\n\tsize_t      Size;           // Size in bytes\n\tconst char* Name;           // Short descriptive name for the type, for debugging\n\tconst char* PrintFmt;       // Default printf format for the type\n\tconst char* ScanFmt;        // Default scanf format for the type\n};\n\n// Extend ImGuiDataType_\nenum ImGuiDataTypePrivate_\n{\n\tImGuiDataType_String = ImGuiDataType_COUNT + 1,\n\tImGuiDataType_Pointer,\n\tImGuiDataType_ID,\n};\n\n// Stacked color modifier, backup of modified data so we can restore it\nstruct ImGuiColorMod\n{\n\tImGuiCol        Col;\n\tImVec4          BackupValue;\n};\n\n// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.\nstruct ImGuiStyleMod\n{\n\tImGuiStyleVar   VarIdx;\n\tunion { int BackupInt[2]; float BackupFloat[2]; };\n\tImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }\n\tImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }\n\tImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }\n};\n\n// Storage data for BeginComboPreview()/EndComboPreview()\nstruct IMGUI_API ImGuiComboPreviewData\n{\n\tImRect          PreviewRect;\n\tImVec2          BackupCursorPos;\n\tImVec2          BackupCursorMaxPos;\n\tImVec2          BackupCursorPosPrevLine;\n\tfloat           BackupPrevLineTextBaseOffset;\n\tImGuiLayoutType BackupLayout;\n\n\tImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); }\n};\n\n// Stacked storage data for BeginGroup()/EndGroup()\nstruct IMGUI_API ImGuiGroupData\n{\n\tImGuiID     WindowID;\n\tImVec2      BackupCursorPos;\n\tImVec2      BackupCursorMaxPos;\n\tImVec1      BackupIndent;\n\tImVec1      BackupGroupOffset;\n\tImVec2      BackupCurrLineSize;\n\tfloat       BackupCurrLineTextBaseOffset;\n\tImGuiID     BackupActiveIdIsAlive;\n\tbool        BackupActiveIdPreviousFrameIsAlive;\n\tbool        BackupHoveredIdIsAlive;\n\tbool        EmitItem;\n};\n\n// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.\nstruct IMGUI_API ImGuiMenuColumns\n{\n\tImU32       TotalWidth;\n\tImU32       NextTotalWidth;\n\tImU16       Spacing;\n\tImU16       OffsetIcon;         // Always zero for now\n\tImU16       OffsetLabel;        // Offsets are locked in Update()\n\tImU16       OffsetShortcut;\n\tImU16       OffsetMark;\n\tImU16       Widths[4];          // Width of:   Icon, Label, Shortcut, Mark  (accumulators for current frame)\n\n\tImGuiMenuColumns() { memset(this, 0, sizeof(*this)); }\n\tvoid        Update(float spacing, bool window_reappearing);\n\tfloat       DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark);\n\tvoid        CalcNextTotalWidth(bool update_offsets);\n};\n\n// Internal temporary state for deactivating InputText() instances.\nstruct IMGUI_API ImGuiInputTextDeactivatedState\n{\n\tImGuiID            ID;              // widget id owning the text state (which just got deactivated)\n\tImVector<char>     TextA;           // text buffer\n\n\tImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); }\n\tvoid    ClearFreeMemory() { ID = 0; TextA.clear(); }\n};\n// Internal state of the currently focused/edited text input box\n// For a given item ID, access with ImGui::GetInputTextState()\nstruct IMGUI_API ImGuiInputTextState\n{\n\tImGuiContext* Ctx;                    // parent UI context (needs to be set explicitly by parent).\n\tImGuiID                 ID;                     // widget id owning the text state\n\tint                     CurLenW, CurLenA;       // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.\n\tImVector<ImWchar>       TextW;                  // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.\n\tImVector<char>          TextA;                  // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.\n\tImVector<char>          InitialTextA;           // backup of end-user buffer at the time of focus (in UTF-8, unaltered)\n\tbool                    TextAIsValid;           // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)\n\tint                     BufCapacityA;           // end-user buffer capacity\n\tfloat                   ScrollX;                // horizontal scrolling/offset\n\tImStb::STB_TexteditState Stb;                   // state for stb_textedit.h\n\tfloat                   CursorAnim;             // timer for cursor blink, reset on every user action so the cursor reappears immediately\n\tbool                    CursorFollow;           // set when we want scrolling to follow the current cursor position (not always!)\n\tbool                    SelectedAllMouseLock;   // after a double-click to select all, we ignore further mouse drags to update selection\n\tbool                    Edited;                 // edited this frame\n\tImGuiInputTextFlags     Flags;                  // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.\n\n\tImGuiInputTextState() { memset(this, 0, sizeof(*this)); }\n\tvoid        ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }\n\tvoid        ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); }\n\tint         GetUndoAvailCount() const { return Stb.undostate.undo_point; }\n\tint         GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; }\n\tvoid        OnKeyPressed(int key);      // Cannot be inline because we call in code in stb_textedit.h implementation\n\n\t// Cursor & Selection\n\tvoid        CursorAnimReset() { CursorAnim = -0.30f; }                                   // After a user-input the cursor stays on for a while without blinking\n\tvoid        CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }\n\tbool        HasSelection() const { return Stb.select_start != Stb.select_end; }\n\tvoid        ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; }\n\tint         GetCursorPos() const { return Stb.cursor; }\n\tint         GetSelectionStart() const { return Stb.select_start; }\n\tint         GetSelectionEnd() const { return Stb.select_end; }\n\tvoid        SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; }\n};\n\n// Storage for current popup stack\nstruct ImGuiPopupData\n{\n\tImGuiID             PopupId;        // Set on OpenPopup()\n\tImGuiWindow* Window;         // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()\n\tImGuiWindow* BackupNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close\n\tint                 ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as \"not any of layers\" value\n\tint                 OpenFrameCount; // Set on OpenPopup()\n\tImGuiID             OpenParentId;   // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items)\n\tImVec2              OpenPopupPos;   // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse)\n\tImVec2              OpenMousePos;   // Set on OpenPopup(), copy of mouse position at the time of opening popup\n\n\tImGuiPopupData() { memset(this, 0, sizeof(*this)); ParentNavLayer = OpenFrameCount = -1; }\n};\n\nenum ImGuiNextWindowDataFlags_\n{\n\tImGuiNextWindowDataFlags_None = 0,\n\tImGuiNextWindowDataFlags_HasPos = 1 << 0,\n\tImGuiNextWindowDataFlags_HasSize = 1 << 1,\n\tImGuiNextWindowDataFlags_HasContentSize = 1 << 2,\n\tImGuiNextWindowDataFlags_HasCollapsed = 1 << 3,\n\tImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4,\n\tImGuiNextWindowDataFlags_HasFocus = 1 << 5,\n\tImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6,\n\tImGuiNextWindowDataFlags_HasScroll = 1 << 7,\n};\n\n// Storage for SetNexWindow** functions\nstruct ImGuiNextWindowData\n{\n\tImGuiNextWindowDataFlags    Flags;\n\tImGuiCond                   PosCond;\n\tImGuiCond                   SizeCond;\n\tImGuiCond                   CollapsedCond;\n\tImVec2                      PosVal;\n\tImVec2                      PosPivotVal;\n\tImVec2                      SizeVal;\n\tImVec2                      ContentSizeVal;\n\tImVec2                      ScrollVal;\n\tbool                        CollapsedVal;\n\tImRect                      SizeConstraintRect;\n\tImGuiSizeCallback           SizeCallback;\n\tvoid* SizeCallbackUserData;\n\tfloat                       BgAlphaVal;             // Override background alpha\n\tImVec2                      MenuBarOffsetMinVal;    // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?)\n\n\tImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }\n\tinline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }\n};\n\nenum ImGuiNextItemDataFlags_\n{\n\tImGuiNextItemDataFlags_None = 0,\n\tImGuiNextItemDataFlags_HasWidth = 1 << 0,\n\tImGuiNextItemDataFlags_HasOpen = 1 << 1,\n};\n\nstruct ImGuiNextItemData\n{\n\tImGuiNextItemDataFlags      Flags;\n\tImGuiItemFlags              ItemFlags;      // Currently only tested/used for ImGuiItemFlags_AllowOverlap.\n\tfloat                       Width;          // Set by SetNextItemWidth()\n\tImGuiID                     FocusScopeId;   // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging)\n\tImGuiCond                   OpenCond;\n\tbool                        OpenVal;        // Set by SetNextItemOpen()\n\n\tImGuiNextItemData() { memset(this, 0, sizeof(*this)); }\n\tinline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()!\n};\n\n// Status storage for the last submitted item\nstruct ImGuiLastItemData\n{\n\tImGuiID                 ID;\n\tImGuiItemFlags          InFlags;            // See ImGuiItemFlags_\n\tImGuiItemStatusFlags    StatusFlags;        // See ImGuiItemStatusFlags_\n\tImRect                  Rect;               // Full rectangle\n\tImRect                  NavRect;            // Navigation scoring rectangle (not displayed)\n\tImRect                  DisplayRect;        // Display rectangle (only if ImGuiItemStatusFlags_HasDisplayRect is set)\n\n\tImGuiLastItemData() { memset(this, 0, sizeof(*this)); }\n};\n\n// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere.\n// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop()\n// Only stored when the node is a potential candidate for landing on a Left arrow jump.\nstruct ImGuiNavTreeNodeData\n{\n\tImGuiID                 ID;\n\tImGuiItemFlags          InFlags;\n\tImRect                  NavRect;\n};\n\nstruct IMGUI_API ImGuiStackSizes\n{\n\tshort   SizeOfIDStack;\n\tshort   SizeOfColorStack;\n\tshort   SizeOfStyleVarStack;\n\tshort   SizeOfFontStack;\n\tshort   SizeOfFocusScopeStack;\n\tshort   SizeOfGroupStack;\n\tshort   SizeOfItemFlagsStack;\n\tshort   SizeOfBeginPopupStack;\n\tshort   SizeOfDisabledStack;\n\n\tImGuiStackSizes() { memset(this, 0, sizeof(*this)); }\n\tvoid SetToContextState(ImGuiContext* ctx);\n\tvoid CompareWithContextState(ImGuiContext* ctx);\n};\n\n// Data saved for each window pushed into the stack\nstruct ImGuiWindowStackData\n{\n\tImGuiWindow* Window;\n\tImGuiLastItemData       ParentLastItemDataBackup;\n\tImGuiStackSizes         StackSizesOnBegin;      // Store size of various stacks for asserting\n};\n\nstruct ImGuiShrinkWidthItem\n{\n\tint         Index;\n\tfloat       Width;\n\tfloat       InitialWidth;\n};\n\nstruct ImGuiPtrOrIndex\n{\n\tvoid* Ptr;            // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool.\n\tint         Index;          // Usually index in a main pool.\n\n\tImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; }\n\tImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Inputs support\n//-----------------------------------------------------------------------------\n\n// Bit array for named keys\ntypedef ImBitArray<ImGuiKey_NamedKey_COUNT, -ImGuiKey_NamedKey_BEGIN>    ImBitArrayForNamedKeys;\n\n// [Internal] Key ranges\n#define ImGuiKey_LegacyNativeKey_BEGIN  0\n#define ImGuiKey_LegacyNativeKey_END    512\n#define ImGuiKey_Keyboard_BEGIN         (ImGuiKey_NamedKey_BEGIN)\n#define ImGuiKey_Keyboard_END           (ImGuiKey_GamepadStart)\n#define ImGuiKey_Gamepad_BEGIN          (ImGuiKey_GamepadStart)\n#define ImGuiKey_Gamepad_END            (ImGuiKey_GamepadRStickDown + 1)\n#define ImGuiKey_Mouse_BEGIN            (ImGuiKey_MouseLeft)\n#define ImGuiKey_Mouse_END              (ImGuiKey_MouseWheelY + 1)\n#define ImGuiKey_Aliases_BEGIN          (ImGuiKey_Mouse_BEGIN)\n#define ImGuiKey_Aliases_END            (ImGuiKey_Mouse_END)\n\n// [Internal] Named shortcuts for Navigation\n#define ImGuiKey_NavKeyboardTweakSlow   ImGuiMod_Ctrl\n#define ImGuiKey_NavKeyboardTweakFast   ImGuiMod_Shift\n#define ImGuiKey_NavGamepadTweakSlow    ImGuiKey_GamepadL1\n#define ImGuiKey_NavGamepadTweakFast    ImGuiKey_GamepadR1\n#define ImGuiKey_NavGamepadActivate     ImGuiKey_GamepadFaceDown\n#define ImGuiKey_NavGamepadCancel       ImGuiKey_GamepadFaceRight\n#define ImGuiKey_NavGamepadMenu         ImGuiKey_GamepadFaceLeft\n#define ImGuiKey_NavGamepadInput        ImGuiKey_GamepadFaceUp\n\nenum ImGuiInputEventType\n{\n\tImGuiInputEventType_None = 0,\n\tImGuiInputEventType_MousePos,\n\tImGuiInputEventType_MouseWheel,\n\tImGuiInputEventType_MouseButton,\n\tImGuiInputEventType_Key,\n\tImGuiInputEventType_Text,\n\tImGuiInputEventType_Focus,\n\tImGuiInputEventType_COUNT\n};\n\nenum ImGuiInputSource\n{\n\tImGuiInputSource_None = 0,\n\tImGuiInputSource_Mouse,         // Note: may be Mouse or TouchScreen or Pen. See io.MouseSource to distinguish them.\n\tImGuiInputSource_Keyboard,\n\tImGuiInputSource_Gamepad,\n\tImGuiInputSource_Clipboard,     // Currently only used by InputText()\n\tImGuiInputSource_COUNT\n};\n\n// FIXME: Structures in the union below need to be declared as anonymous unions appears to be an extension?\n// Using ImVec2() would fail on Clang 'union member 'MousePos' has a non-trivial default constructor'\nstruct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; };\nstruct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; };\nstruct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; };\nstruct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; };\nstruct ImGuiInputEventText { unsigned int Char; };\nstruct ImGuiInputEventAppFocused { bool Focused; };\n\nstruct ImGuiInputEvent\n{\n\tImGuiInputEventType             Type;\n\tImGuiInputSource                Source;\n\tImU32                           EventId;        // Unique, sequential increasing integer to identify an event (if you need to correlate them to other data).\n\tunion\n\t{\n\t\tImGuiInputEventMousePos     MousePos;       // if Type == ImGuiInputEventType_MousePos\n\t\tImGuiInputEventMouseWheel   MouseWheel;     // if Type == ImGuiInputEventType_MouseWheel\n\t\tImGuiInputEventMouseButton  MouseButton;    // if Type == ImGuiInputEventType_MouseButton\n\t\tImGuiInputEventKey          Key;            // if Type == ImGuiInputEventType_Key\n\t\tImGuiInputEventText         Text;           // if Type == ImGuiInputEventType_Text\n\t\tImGuiInputEventAppFocused   AppFocused;     // if Type == ImGuiInputEventType_Focus\n\t};\n\tbool                            AddedByTestEngine;\n\n\tImGuiInputEvent() { memset(this, 0, sizeof(*this)); }\n};\n\n// Input function taking an 'ImGuiID owner_id' argument defaults to (ImGuiKeyOwner_Any == 0) aka don't test ownership, which matches legacy behavior.\n#define ImGuiKeyOwner_Any           ((ImGuiID)0)    // Accept key that have an owner, UNLESS a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease.\n#define ImGuiKeyOwner_None          ((ImGuiID)-1)   // Require key to have no owner.\n\ntypedef ImS16 ImGuiKeyRoutingIndex;\n\n// Routing table entry (sizeof() == 16 bytes)\nstruct ImGuiKeyRoutingData\n{\n\tImGuiKeyRoutingIndex            NextEntryIndex;\n\tImU16                           Mods;               // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super.\n\tImU8                            RoutingNextScore;   // Lower is better (0: perfect score)\n\tImGuiID                         RoutingCurr;\n\tImGuiID                         RoutingNext;\n\n\tImGuiKeyRoutingData() { NextEntryIndex = -1; Mods = 0; RoutingNextScore = 255; RoutingCurr = RoutingNext = ImGuiKeyOwner_None; }\n};\n\n// Routing table: maintain a desired owner for each possible key-chord (key + mods), and setup owner in NewFrame() when mods are matching.\n// Stored in main context (1 instance)\nstruct ImGuiKeyRoutingTable\n{\n\tImGuiKeyRoutingIndex            Index[ImGuiKey_NamedKey_COUNT]; // Index of first entry in Entries[]\n\tImVector<ImGuiKeyRoutingData>   Entries;\n\tImVector<ImGuiKeyRoutingData>   EntriesNext;                    // Double-buffer to avoid reallocation (could use a shared buffer)\n\n\tImGuiKeyRoutingTable() { Clear(); }\n\tvoid Clear() { for (int n = 0; n < IM_ARRAYSIZE(Index); n++) Index[n] = -1; Entries.clear(); EntriesNext.clear(); }\n};\n\n// This extends ImGuiKeyData but only for named keys (legacy keys don't support the new features)\n// Stored in main context (1 per named key). In the future it might be merged into ImGuiKeyData.\nstruct ImGuiKeyOwnerData\n{\n\tImGuiID     OwnerCurr;\n\tImGuiID     OwnerNext;\n\tbool        LockThisFrame;      // Reading this key requires explicit owner id (until end of frame). Set by ImGuiInputFlags_LockThisFrame.\n\tbool        LockUntilRelease;   // Reading this key requires explicit owner id (until key is released). Set by ImGuiInputFlags_LockUntilRelease. When this is true LockThisFrame is always true as well.\n\n\tImGuiKeyOwnerData() { OwnerCurr = OwnerNext = ImGuiKeyOwner_None; LockThisFrame = LockUntilRelease = false; }\n};\n\n// Flags for extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner()\n// Don't mistake with ImGuiInputTextFlags! (for ImGui::InputText() function)\nenum ImGuiInputFlags_\n{\n\t// Flags for IsKeyPressed(), IsMouseClicked(), Shortcut()\n\tImGuiInputFlags_None = 0,\n\tImGuiInputFlags_Repeat = 1 << 0,   // Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1.\n\tImGuiInputFlags_RepeatRateDefault = 1 << 1,   // Repeat rate: Regular (default)\n\tImGuiInputFlags_RepeatRateNavMove = 1 << 2,   // Repeat rate: Fast\n\tImGuiInputFlags_RepeatRateNavTweak = 1 << 3,   // Repeat rate: Faster\n\tImGuiInputFlags_RepeatRateMask_ = ImGuiInputFlags_RepeatRateDefault | ImGuiInputFlags_RepeatRateNavMove | ImGuiInputFlags_RepeatRateNavTweak,\n\n\t// Flags for SetItemKeyOwner()\n\tImGuiInputFlags_CondHovered = 1 << 4,   // Only set if item is hovered (default to both)\n\tImGuiInputFlags_CondActive = 1 << 5,   // Only set if item is active (default to both)\n\tImGuiInputFlags_CondDefault_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive,\n\tImGuiInputFlags_CondMask_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive,\n\n\t// Flags for SetKeyOwner(), SetItemKeyOwner()\n\tImGuiInputFlags_LockThisFrame = 1 << 6,   // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared at end of frame. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code.\n\tImGuiInputFlags_LockUntilRelease = 1 << 7,   // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared when the key is released or at end of each frame if key is released. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code.\n\n\t// Routing policies for Shortcut() + low-level SetShortcutRouting()\n\t// - The general idea is that several callers register interest in a shortcut, and only one owner gets it.\n\t// - When a policy (other than _RouteAlways) is set, Shortcut() will register itself with SetShortcutRouting(),\n\t//   allowing the system to decide where to route the input among other route-aware calls.\n\t// - Shortcut() uses ImGuiInputFlags_RouteFocused by default: meaning that a simple Shortcut() poll\n\t//   will register a route and only succeed when parent window is in the focus stack and if no-one\n\t//   with a higher priority is claiming the shortcut.\n\t// - Using ImGuiInputFlags_RouteAlways is roughly equivalent to doing e.g. IsKeyPressed(key) + testing mods.\n\t// - Priorities: GlobalHigh > Focused (when owner is active item) > Global > Focused (when focused window) > GlobalLow.\n\t// - Can select only 1 policy among all available.\n\tImGuiInputFlags_RouteFocused = 1 << 8,   // (Default) Register focused route: Accept inputs if window is in focus stack. Deep-most focused window takes inputs. ActiveId takes inputs over deep-most focused window.\n\tImGuiInputFlags_RouteGlobalLow = 1 << 9,   // Register route globally (lowest priority: unless a focused window or active item registered the route) -> recommended Global priority.\n\tImGuiInputFlags_RouteGlobal = 1 << 10,  // Register route globally (medium priority: unless an active item registered the route, e.g. CTRL+A registered by InputText).\n\tImGuiInputFlags_RouteGlobalHigh = 1 << 11,  // Register route globally (highest priority: unlikely you need to use that: will interfere with every active items)\n\tImGuiInputFlags_RouteMask_ = ImGuiInputFlags_RouteFocused | ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteGlobalLow | ImGuiInputFlags_RouteGlobalHigh, // _Always not part of this!\n\tImGuiInputFlags_RouteAlways = 1 << 12,  // Do not register route, poll keys directly.\n\tImGuiInputFlags_RouteUnlessBgFocused = 1 << 13,  // Global routes will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications.\n\tImGuiInputFlags_RouteExtraMask_ = ImGuiInputFlags_RouteAlways | ImGuiInputFlags_RouteUnlessBgFocused,\n\n\t// [Internal] Mask of which function support which flags\n\tImGuiInputFlags_SupportedByIsKeyPressed = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_,\n\tImGuiInputFlags_SupportedByShortcut = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_ | ImGuiInputFlags_RouteMask_ | ImGuiInputFlags_RouteExtraMask_,\n\tImGuiInputFlags_SupportedBySetKeyOwner = ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease,\n\tImGuiInputFlags_SupportedBySetItemKeyOwner = ImGuiInputFlags_SupportedBySetKeyOwner | ImGuiInputFlags_CondMask_,\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Clipper support\n//-----------------------------------------------------------------------------\n\n// Note that Max is exclusive, so perhaps should be using a Begin/End convention.\nstruct ImGuiListClipperRange\n{\n\tint     Min;\n\tint     Max;\n\tbool    PosToIndexConvert;      // Begin/End are absolute position (will be converted to indices later)\n\tImS8    PosToIndexOffsetMin;    // Add to Min after converting to indices\n\tImS8    PosToIndexOffsetMax;    // Add to Min after converting to indices\n\n\tstatic ImGuiListClipperRange    FromIndices(int min, int max) { ImGuiListClipperRange r = { min, max, false, 0, 0 }; return r; }\n\tstatic ImGuiListClipperRange    FromPositions(float y1, float y2, int off_min, int off_max) { ImGuiListClipperRange r = { (int)y1, (int)y2, true, (ImS8)off_min, (ImS8)off_max }; return r; }\n};\n\n// Temporary clipper data, buffers shared/reused between instances\nstruct ImGuiListClipperData\n{\n\tImGuiListClipper* ListClipper;\n\tfloat                           LossynessOffset;\n\tint                             StepNo;\n\tint                             ItemsFrozen;\n\tImVector<ImGuiListClipperRange> Ranges;\n\n\tImGuiListClipperData() { memset(this, 0, sizeof(*this)); }\n\tvoid                            Reset(ImGuiListClipper* clipper) { ListClipper = clipper; StepNo = ItemsFrozen = 0; Ranges.resize(0); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Navigation support\n//-----------------------------------------------------------------------------\n\nenum ImGuiActivateFlags_\n{\n\tImGuiActivateFlags_None = 0,\n\tImGuiActivateFlags_PreferInput = 1 << 0,       // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default for Enter key.\n\tImGuiActivateFlags_PreferTweak = 1 << 1,       // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default for Space key and if keyboard is not used.\n\tImGuiActivateFlags_TryToPreserveState = 1 << 2,       // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection)\n};\n\n// Early work-in-progress API for ScrollToItem()\nenum ImGuiScrollFlags_\n{\n\tImGuiScrollFlags_None = 0,\n\tImGuiScrollFlags_KeepVisibleEdgeX = 1 << 0,       // If item is not visible: scroll as little as possible on X axis to bring item back into view [default for X axis]\n\tImGuiScrollFlags_KeepVisibleEdgeY = 1 << 1,       // If item is not visible: scroll as little as possible on Y axis to bring item back into view [default for Y axis for windows that are already visible]\n\tImGuiScrollFlags_KeepVisibleCenterX = 1 << 2,       // If item is not visible: scroll to make the item centered on X axis [rarely used]\n\tImGuiScrollFlags_KeepVisibleCenterY = 1 << 3,       // If item is not visible: scroll to make the item centered on Y axis\n\tImGuiScrollFlags_AlwaysCenterX = 1 << 4,       // Always center the result item on X axis [rarely used]\n\tImGuiScrollFlags_AlwaysCenterY = 1 << 5,       // Always center the result item on Y axis [default for Y axis for appearing window)\n\tImGuiScrollFlags_NoScrollParent = 1 << 6,       // Disable forwarding scrolling to parent window if required to keep item/rect visible (only scroll window the function was applied to).\n\tImGuiScrollFlags_MaskX_ = ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleCenterX | ImGuiScrollFlags_AlwaysCenterX,\n\tImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY,\n};\n\nenum ImGuiNavHighlightFlags_\n{\n\tImGuiNavHighlightFlags_None = 0,\n\tImGuiNavHighlightFlags_TypeDefault = 1 << 0,\n\tImGuiNavHighlightFlags_TypeThin = 1 << 1,\n\tImGuiNavHighlightFlags_AlwaysDraw = 1 << 2,       // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse.\n\tImGuiNavHighlightFlags_NoRounding = 1 << 3,\n};\n\nenum ImGuiNavMoveFlags_\n{\n\tImGuiNavMoveFlags_None = 0,\n\tImGuiNavMoveFlags_LoopX = 1 << 0,   // On failed request, restart from opposite side\n\tImGuiNavMoveFlags_LoopY = 1 << 1,\n\tImGuiNavMoveFlags_WrapX = 1 << 2,   // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left)\n\tImGuiNavMoveFlags_WrapY = 1 << 3,   // This is not super useful but provided for completeness\n\tImGuiNavMoveFlags_WrapMask_ = ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_WrapY,\n\tImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4,   // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)\n\tImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5,   // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown)\n\tImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6,   // Force scrolling to min/max (used by Home/End) // FIXME-NAV: Aim to remove or reword, probably unnecessary\n\tImGuiNavMoveFlags_Forwarded = 1 << 7,\n\tImGuiNavMoveFlags_DebugNoResult = 1 << 8,   // Dummy scoring for debug purpose, don't apply result\n\tImGuiNavMoveFlags_FocusApi = 1 << 9,   // Requests from focus API can land/focus/activate items even if they are marked with _NoTabStop (see NavProcessItemForTabbingRequest() for details)\n\tImGuiNavMoveFlags_IsTabbing = 1 << 10,  // == Focus + Activate if item is Inputable + DontChangeNavHighlight\n\tImGuiNavMoveFlags_IsPageMove = 1 << 11,  // Identify a PageDown/PageUp request.\n\tImGuiNavMoveFlags_Activate = 1 << 12,  // Activate/select target item.\n\tImGuiNavMoveFlags_NoSelect = 1 << 13,  // Don't trigger selection by not setting g.NavJustMovedTo\n\tImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14,  // Do not alter the visible state of keyboard vs mouse nav highlight\n};\n\nenum ImGuiNavLayer\n{\n\tImGuiNavLayer_Main = 0,    // Main scrolling layer\n\tImGuiNavLayer_Menu = 1,    // Menu layer (access with Alt)\n\tImGuiNavLayer_COUNT\n};\n\nstruct ImGuiNavItemData\n{\n\tImGuiWindow* Window;         // Init,Move    // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window)\n\tImGuiID             ID;             // Init,Move    // Best candidate item ID\n\tImGuiID             FocusScopeId;   // Init,Move    // Best candidate focus scope ID\n\tImRect              RectRel;        // Init,Move    // Best candidate bounding box in window relative space\n\tImGuiItemFlags      InFlags;        // ????,Move    // Best candidate item flags\n\tfloat               DistBox;        //      Move    // Best candidate box distance to current NavId\n\tfloat               DistCenter;     //      Move    // Best candidate center distance to current NavId\n\tfloat               DistAxial;      //      Move    // Best candidate axial distance to current NavId\n\n\tImGuiNavItemData() { Clear(); }\n\tvoid Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; DistBox = DistCenter = DistAxial = FLT_MAX; }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Columns support\n//-----------------------------------------------------------------------------\n\n// Flags for internal's BeginColumns(). Prefix using BeginTable() nowadays!\nenum ImGuiOldColumnFlags_\n{\n\tImGuiOldColumnFlags_None = 0,\n\tImGuiOldColumnFlags_NoBorder = 1 << 0,   // Disable column dividers\n\tImGuiOldColumnFlags_NoResize = 1 << 1,   // Disable resizing columns when clicking on the dividers\n\tImGuiOldColumnFlags_NoPreserveWidths = 1 << 2,   // Disable column width preservation when adjusting columns\n\tImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3,   // Disable forcing columns to fit within window\n\tImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4,   // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.\n\n\t// Obsolete names (will be removed)\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tImGuiColumnsFlags_None = ImGuiOldColumnFlags_None,\n\tImGuiColumnsFlags_NoBorder = ImGuiOldColumnFlags_NoBorder,\n\tImGuiColumnsFlags_NoResize = ImGuiOldColumnFlags_NoResize,\n\tImGuiColumnsFlags_NoPreserveWidths = ImGuiOldColumnFlags_NoPreserveWidths,\n\tImGuiColumnsFlags_NoForceWithinWindow = ImGuiOldColumnFlags_NoForceWithinWindow,\n\tImGuiColumnsFlags_GrowParentContentsSize = ImGuiOldColumnFlags_GrowParentContentsSize,\n#endif\n};\n\nstruct ImGuiOldColumnData\n{\n\tfloat               OffsetNorm;             // Column start offset, normalized 0.0 (far left) -> 1.0 (far right)\n\tfloat               OffsetNormBeforeResize;\n\tImGuiOldColumnFlags Flags;                  // Not exposed\n\tImRect              ClipRect;\n\n\tImGuiOldColumnData() { memset(this, 0, sizeof(*this)); }\n};\n\nstruct ImGuiOldColumns\n{\n\tImGuiID             ID;\n\tImGuiOldColumnFlags Flags;\n\tbool                IsFirstFrame;\n\tbool                IsBeingResized;\n\tint                 Current;\n\tint                 Count;\n\tfloat               OffMinX, OffMaxX;       // Offsets from HostWorkRect.Min.x\n\tfloat               LineMinY, LineMaxY;\n\tfloat               HostCursorPosY;         // Backup of CursorPos at the time of BeginColumns()\n\tfloat               HostCursorMaxPosX;      // Backup of CursorMaxPos at the time of BeginColumns()\n\tImRect              HostInitialClipRect;    // Backup of ClipRect at the time of BeginColumns()\n\tImRect              HostBackupClipRect;     // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground()\n\tImRect              HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns()\n\tImVector<ImGuiOldColumnData> Columns;\n\tImDrawListSplitter  Splitter;\n\n\tImGuiOldColumns() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Multi-select support\n//-----------------------------------------------------------------------------\n\n#ifdef IMGUI_HAS_MULTI_SELECT\n// <this is filled in 'range_select' branch>\n#endif // #ifdef IMGUI_HAS_MULTI_SELECT\n\n//-----------------------------------------------------------------------------\n// [SECTION] Docking support\n//-----------------------------------------------------------------------------\n\n#ifdef IMGUI_HAS_DOCK\n// <this is filled in 'docking' branch>\n#endif // #ifdef IMGUI_HAS_DOCK\n\n//-----------------------------------------------------------------------------\n// [SECTION] Viewport support\n//-----------------------------------------------------------------------------\n\n// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!)\n// Every instance of ImGuiViewport is in fact a ImGuiViewportP.\nstruct ImGuiViewportP : public ImGuiViewport\n{\n\tint                 BgFgDrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used\n\tImDrawList* BgFgDrawLists[2];       // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.\n\tImDrawData          DrawDataP;\n\tImDrawDataBuilder   DrawDataBuilder;        // Temporary data while building final ImDrawData\n\tImVec2              WorkOffsetMin;          // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!)\n\tImVec2              WorkOffsetMax;          // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height).\n\tImVec2              BuildWorkOffsetMin;     // Work Area: Offset being built during current frame. Generally >= 0.0f.\n\tImVec2              BuildWorkOffsetMax;     // Work Area: Offset being built during current frame. Generally <= 0.0f.\n\n\tImGuiViewportP() { BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; }\n\t~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }\n\n\t// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)\n\tImVec2  CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); }\n\tImVec2  CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); }\n\tvoid    UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields\n\n\t// Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry)\n\tImRect  GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }\n\tImRect  GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }\n\tImRect  GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Settings support\n//-----------------------------------------------------------------------------\n\n// Windows data saved in imgui.ini file\n// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily.\n// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure)\nstruct ImGuiWindowSettings\n{\n\tImGuiID     ID;\n\tImVec2ih    Pos;\n\tImVec2ih    Size;\n\tbool        Collapsed;\n\tbool        WantApply;      // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)\n\tbool        WantDelete;     // Set to invalidate/delete the settings entry\n\n\tImGuiWindowSettings() { memset(this, 0, sizeof(*this)); }\n\tchar* GetName() { return (char*)(this + 1); }\n};\n\nstruct ImGuiSettingsHandler\n{\n\tconst char* TypeName;       // Short description stored in .ini file. Disallowed characters: '[' ']'\n\tImGuiID     TypeHash;       // == ImHashStr(TypeName)\n\tvoid        (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Clear all settings data\n\tvoid        (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Read: Called before reading (in registration order)\n\tvoid* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name);              // Read: Called when entering into a new ini entry e.g. \"[Window][Name]\"\n\tvoid        (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry\n\tvoid        (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Read: Called after reading (in registration order)\n\tvoid        (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf);      // Write: Output every entries into 'out_buf'\n\tvoid* UserData;\n\n\tImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Localization support\n//-----------------------------------------------------------------------------\n\n// This is experimental and not officially supported, it'll probably fall short of features, if/when it does we may backtrack.\nenum ImGuiLocKey : int\n{\n\tImGuiLocKey_VersionStr,\n\tImGuiLocKey_TableSizeOne,\n\tImGuiLocKey_TableSizeAllFit,\n\tImGuiLocKey_TableSizeAllDefault,\n\tImGuiLocKey_TableResetOrder,\n\tImGuiLocKey_WindowingMainMenuBar,\n\tImGuiLocKey_WindowingPopup,\n\tImGuiLocKey_WindowingUntitled,\n\tImGuiLocKey_COUNT\n};\n\nstruct ImGuiLocEntry\n{\n\tImGuiLocKey     Key;\n\tconst char* Text;\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Metrics, Debug Tools\n//-----------------------------------------------------------------------------\n\nenum ImGuiDebugLogFlags_\n{\n\t// Event types\n\tImGuiDebugLogFlags_None = 0,\n\tImGuiDebugLogFlags_EventActiveId = 1 << 0,\n\tImGuiDebugLogFlags_EventFocus = 1 << 1,\n\tImGuiDebugLogFlags_EventPopup = 1 << 2,\n\tImGuiDebugLogFlags_EventNav = 1 << 3,\n\tImGuiDebugLogFlags_EventClipper = 1 << 4,\n\tImGuiDebugLogFlags_EventSelection = 1 << 5,\n\tImGuiDebugLogFlags_EventIO = 1 << 6,\n\tImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO,\n\tImGuiDebugLogFlags_OutputToTTY = 1 << 10,  // Also send output to TTY\n};\n\nstruct ImGuiMetricsConfig\n{\n\tbool        ShowDebugLog = false;\n\tbool        ShowStackTool = false;\n\tbool        ShowWindowsRects = false;\n\tbool        ShowWindowsBeginOrder = false;\n\tbool        ShowTablesRects = false;\n\tbool        ShowDrawCmdMesh = true;\n\tbool        ShowDrawCmdBoundingBoxes = true;\n\tbool        ShowAtlasTintedWithTextColor = false;\n\tint         ShowWindowsRectsType = -1;\n\tint         ShowTablesRectsType = -1;\n};\n\nstruct ImGuiStackLevelInfo\n{\n\tImGuiID                 ID;\n\tImS8                    QueryFrameCount;            // >= 1: Query in progress\n\tbool                    QuerySuccess;               // Obtained result from DebugHookIdInfo()\n\tImGuiDataType           DataType : 8;\n\tchar                    Desc[57];                   // Arbitrarily sized buffer to hold a result (FIXME: could replace Results[] with a chunk stream?) FIXME: Now that we added CTRL+C this should be fixed.\n\n\tImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); }\n};\n\n// State for Stack tool queries\nstruct ImGuiStackTool\n{\n\tint                     LastActiveFrame;\n\tint                     StackLevel;                 // -1: query stack and resize Results, >= 0: individual stack level\n\tImGuiID                 QueryId;                    // ID to query details for\n\tImVector<ImGuiStackLevelInfo> Results;\n\tbool                    CopyToClipboardOnCtrlC;\n\tfloat                   CopyToClipboardLastTime;\n\n\tImGuiStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Generic context hooks\n//-----------------------------------------------------------------------------\n\ntypedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook);\nenum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ };\n\nstruct ImGuiContextHook\n{\n\tImGuiID                     HookId;     // A unique ID assigned by AddContextHook()\n\tImGuiContextHookType        Type;\n\tImGuiID                     Owner;\n\tImGuiContextHookCallback    Callback;\n\tvoid* UserData;\n\n\tImGuiContextHook() { memset(this, 0, sizeof(*this)); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiContext (main Dear ImGui context)\n//-----------------------------------------------------------------------------\n\nstruct ImGuiContext\n{\n\tbool                    Initialized;\n\tbool                    FontAtlasOwnedByContext;            // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it.\n\tImGuiIO                 IO;\n\tImGuiStyle              Style;\n\tImFont* Font;                               // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()\n\tfloat                   FontSize;                           // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.\n\tfloat                   FontBaseSize;                       // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.\n\tImDrawListSharedData    DrawListSharedData;\n\tdouble                  Time;\n\tint                     FrameCount;\n\tint                     FrameCountEnded;\n\tint                     FrameCountRendered;\n\tbool                    WithinFrameScope;                   // Set by NewFrame(), cleared by EndFrame()\n\tbool                    WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed\n\tbool                    WithinEndChild;                     // Set within EndChild()\n\tbool                    GcCompactAll;                       // Request full GC\n\tbool                    TestEngineHookItems;                // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()\n\tvoid* TestEngine;                         // Test engine user data\n\n\t// Inputs\n\tImVector<ImGuiInputEvent> InputEventsQueue;                 // Input events which will be trickled/written into IO structure.\n\tImVector<ImGuiInputEvent> InputEventsTrail;                 // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail.\n\tImGuiMouseSource        InputEventsNextMouseSource;\n\tImU32                   InputEventsNextEventId;\n\n\t// Windows state\n\tImVector<ImGuiWindow*>  Windows;                            // Windows, sorted in display order, back to front\n\tImVector<ImGuiWindow*>  WindowsFocusOrder;                  // Root windows, sorted in focus order, back to front.\n\tImVector<ImGuiWindow*>  WindowsTempSortBuffer;              // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child\n\tImVector<ImGuiWindowStackData> CurrentWindowStack;\n\tImGuiStorage            WindowsById;                        // Map window's ImGuiID to ImGuiWindow*\n\tint                     WindowsActiveCount;                 // Number of unique windows submitted by frame\n\tImVec2                  WindowsHoverPadding;                // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING)\n\tImGuiWindow* CurrentWindow;                      // Window being drawn into\n\tImGuiWindow* HoveredWindow;                      // Window the mouse is hovering. Will typically catch mouse inputs.\n\tImGuiWindow* HoveredWindowUnderMovingWindow;     // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.\n\tImGuiWindow* MovingWindow;                       // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow.\n\tImGuiWindow* WheelingWindow;                     // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.\n\tImVec2                  WheelingWindowRefMousePos;\n\tint                     WheelingWindowStartFrame;           // This may be set one frame before WheelingWindow is != NULL\n\tfloat                   WheelingWindowReleaseTimer;\n\tImVec2                  WheelingWindowWheelRemainder;\n\tImVec2                  WheelingAxisAvg;\n\n\t// Item/widgets state and tracking information\n\tImGuiID                 DebugHookIdInfo;                    // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]\n\tImGuiID                 HoveredId;                          // Hovered widget, filled during the frame\n\tImGuiID                 HoveredIdPreviousFrame;\n\tbool                    HoveredIdAllowOverlap;\n\tbool                    HoveredIdDisabled;                  // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.\n\tfloat                   HoveredIdTimer;                     // Measure contiguous hovering time\n\tfloat                   HoveredIdNotActiveTimer;            // Measure contiguous hovering time where the item has not been active\n\tImGuiID                 ActiveId;                           // Active widget\n\tImGuiID                 ActiveIdIsAlive;                    // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)\n\tfloat                   ActiveIdTimer;\n\tbool                    ActiveIdIsJustActivated;            // Set at the time of activation for one frame\n\tbool                    ActiveIdAllowOverlap;               // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)\n\tbool                    ActiveIdNoClearOnFocusLoss;         // Disable losing active id if the active id window gets unfocused.\n\tbool                    ActiveIdHasBeenPressedBefore;       // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.\n\tbool                    ActiveIdHasBeenEditedBefore;        // Was the value associated to the widget Edited over the course of the Active state.\n\tbool                    ActiveIdHasBeenEditedThisFrame;\n\tImVec2                  ActiveIdClickOffset;                // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)\n\tImGuiWindow* ActiveIdWindow;\n\tImGuiInputSource        ActiveIdSource;                     // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad\n\tint                     ActiveIdMouseButton;\n\tImGuiID                 ActiveIdPreviousFrame;\n\tbool                    ActiveIdPreviousFrameIsAlive;\n\tbool                    ActiveIdPreviousFrameHasBeenEditedBefore;\n\tImGuiWindow* ActiveIdPreviousFrameWindow;\n\tImGuiID                 LastActiveId;                       // Store the last non-zero ActiveId, useful for animation.\n\tfloat                   LastActiveIdTimer;                  // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.\n\n\t// [EXPERIMENTAL] Key/Input Ownership + Shortcut Routing system\n\t// - The idea is that instead of \"eating\" a given key, we can link to an owner.\n\t// - Input query can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID.\n\t// - Routing is requested ahead of time for a given chord (Key + Mods) and granted in NewFrame().\n\tImGuiKeyOwnerData       KeysOwnerData[ImGuiKey_NamedKey_COUNT];\n\tImGuiKeyRoutingTable    KeysRoutingTable;\n\tImU32                   ActiveIdUsingNavDirMask;            // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)\n\tbool                    ActiveIdUsingAllKeyboardKeys;       // Active widget will want to read all keyboard keys inputs. (FIXME: This is a shortcut for not taking ownership of 100+ keys but perhaps best to not have the inconsistency)\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tImU32                   ActiveIdUsingNavInputMask;          // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);'\n#endif\n\n\t// Next window/item data\n\tImGuiID                 CurrentFocusScopeId;                // == g.FocusScopeStack.back()\n\tImGuiItemFlags          CurrentItemFlags;                   // == g.ItemFlagsStack.back()\n\tImGuiID                 DebugLocateId;                      // Storage for DebugLocateItemOnHover() feature: this is read by ItemAdd() so we keep it in a hot/cached location\n\tImGuiNextItemData       NextItemData;                       // Storage for SetNextItem** functions\n\tImGuiLastItemData       LastItemData;                       // Storage for last submitted item (setup by ItemAdd)\n\tImGuiNextWindowData     NextWindowData;                     // Storage for SetNextWindow** functions\n\n\t// Shared stacks\n\tImVector<ImGuiColorMod> ColorStack;                         // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin()\n\tImVector<ImGuiStyleMod> StyleVarStack;                      // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin()\n\tImVector<ImFont*>       FontStack;                          // Stack for PushFont()/PopFont() - inherited by Begin()\n\tImVector<ImGuiID>       FocusScopeStack;                    // Stack for PushFocusScope()/PopFocusScope() - inherited by BeginChild(), pushed into by Begin()\n\tImVector<ImGuiItemFlags>ItemFlagsStack;                     // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin()\n\tImVector<ImGuiGroupData>GroupStack;                         // Stack for BeginGroup()/EndGroup() - not inherited by Begin()\n\tImVector<ImGuiPopupData>OpenPopupStack;                     // Which popups are open (persistent)\n\tImVector<ImGuiPopupData>BeginPopupStack;                    // Which level of BeginPopup() we are in (reset every frame)\n\tImVector<ImGuiNavTreeNodeData> NavTreeNodeStack;            // Stack for TreeNode() when a NavLeft requested is emitted.\n\n\tint                     BeginMenuCount;\n\n\t// Viewports\n\tImVector<ImGuiViewportP*> Viewports;                        // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData.\n\n\t// Gamepad/keyboard Navigation\n\tImGuiWindow* NavWindow;                          // Focused window for navigation. Could be called 'FocusedWindow'\n\tImGuiID                 NavId;                              // Focused item for navigation\n\tImGuiID                 NavFocusScopeId;                    // Identify a selection scope (selection code often wants to \"clear other items\" when landing on an item of the selection set)\n\tImGuiID                 NavActivateId;                      // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem()\n\tImGuiID                 NavActivateDownId;                  // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0\n\tImGuiID                 NavActivatePressedId;               // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)\n\tImGuiActivateFlags      NavActivateFlags;\n\tImGuiID                 NavJustMovedToId;                   // Just navigated to this id (result of a successfully MoveRequest).\n\tImGuiID                 NavJustMovedToFocusScopeId;         // Just navigated to this focus scope id (result of a successfully MoveRequest).\n\tImGuiKeyChord           NavJustMovedToKeyMods;\n\tImGuiID                 NavNextActivateId;                  // Set by ActivateItem(), queued until next frame.\n\tImGuiActivateFlags      NavNextActivateFlags;\n\tImGuiInputSource        NavInputSource;                     // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse\n\tImGuiNavLayer           NavLayer;                           // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.\n\tbool                    NavIdIsAlive;                       // Nav widget has been seen this frame ~~ NavRectRel is valid\n\tbool                    NavMousePosDirty;                   // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)\n\tbool                    NavDisableHighlight;                // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover)\n\tbool                    NavDisableMouseHover;               // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again.\n\n\t// Navigation: Init & Move Requests\n\tbool                    NavAnyRequest;                      // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd()\n\tbool                    NavInitRequest;                     // Init request for appearing window to select first item\n\tbool                    NavInitRequestFromMove;\n\tImGuiNavItemData        NavInitResult;                      // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called)\n\tbool                    NavMoveSubmitted;                   // Move request submitted, will process result on next NewFrame()\n\tbool                    NavMoveScoringItems;                // Move request submitted, still scoring incoming items\n\tbool                    NavMoveForwardToNextFrame;\n\tImGuiNavMoveFlags       NavMoveFlags;\n\tImGuiScrollFlags        NavMoveScrollFlags;\n\tImGuiKeyChord           NavMoveKeyMods;\n\tImGuiDir                NavMoveDir;                         // Direction of the move request (left/right/up/down)\n\tImGuiDir                NavMoveDirForDebug;\n\tImGuiDir                NavMoveClipDir;                     // FIXME-NAV: Describe the purpose of this better. Might want to rename?\n\tImRect                  NavScoringRect;                     // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring.\n\tImRect                  NavScoringNoClipRect;               // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted\n\tint                     NavScoringDebugCount;               // Metrics for debugging\n\tint                     NavTabbingDir;                      // Generally -1 or +1, 0 when tabbing without a nav id\n\tint                     NavTabbingCounter;                  // >0 when counting items for tabbing\n\tImGuiNavItemData        NavMoveResultLocal;                 // Best move request candidate within NavWindow\n\tImGuiNavItemData        NavMoveResultLocalVisible;          // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)\n\tImGuiNavItemData        NavMoveResultOther;                 // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)\n\tImGuiNavItemData        NavTabbingResultFirst;              // First tabbing request candidate within NavWindow and flattened hierarchy\n\n\t// Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize)\n\tImGuiKeyChord           ConfigNavWindowingKeyNext;          // = ImGuiMod_Ctrl | ImGuiKey_Tab, for reconfiguration (see #4828)\n\tImGuiKeyChord           ConfigNavWindowingKeyPrev;          // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab\n\tImGuiWindow* NavWindowingTarget;                 // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most!\n\tImGuiWindow* NavWindowingTargetAnim;             // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it.\n\tImGuiWindow* NavWindowingListWindow;             // Internal window actually listing the CTRL+Tab contents\n\tfloat                   NavWindowingTimer;\n\tfloat                   NavWindowingHighlightAlpha;\n\tbool                    NavWindowingToggleLayer;\n\tImVec2                  NavWindowingAccumDeltaPos;\n\tImVec2                  NavWindowingAccumDeltaSize;\n\n\t// Render\n\tfloat                   DimBgRatio;                         // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list)\n\n\t// Drag and Drop\n\tbool                    DragDropActive;\n\tbool                    DragDropWithinSource;               // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source.\n\tbool                    DragDropWithinTarget;               // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target.\n\tImGuiDragDropFlags      DragDropSourceFlags;\n\tint                     DragDropSourceFrameCount;\n\tint                     DragDropMouseButton;\n\tImGuiPayload            DragDropPayload;\n\tImRect                  DragDropTargetRect;                 // Store rectangle of current target candidate (we favor small targets when overlapping)\n\tImGuiID                 DragDropTargetId;\n\tImGuiDragDropFlags      DragDropAcceptFlags;\n\tfloat                   DragDropAcceptIdCurrRectSurface;    // Target item surface (we resolve overlapping targets by prioritizing the smaller surface)\n\tImGuiID                 DragDropAcceptIdCurr;               // Target item id (set at the time of accepting the payload)\n\tImGuiID                 DragDropAcceptIdPrev;               // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets)\n\tint                     DragDropAcceptFrameCount;           // Last time a target expressed a desire to accept the source\n\tImGuiID                 DragDropHoldJustPressedId;          // Set when holding a payload just made ButtonBehavior() return a press.\n\tImVector<unsigned char> DragDropPayloadBufHeap;             // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size\n\tunsigned char           DragDropPayloadBufLocal[16];        // Local buffer for small payloads\n\n\t// Clipper\n\tint                             ClipperTempDataStacked;\n\tImVector<ImGuiListClipperData>  ClipperTempData;\n\n\t// Tables\n\tImGuiTable* CurrentTable;\n\tint                             TablesTempDataStacked;      // Temporary table data size (because we leave previous instances undestructed, we generally don't use TablesTempData.Size)\n\tImVector<ImGuiTableTempData>    TablesTempData;             // Temporary table data (buffers reused/shared across instances, support nesting)\n\tImPool<ImGuiTable>              Tables;                     // Persistent table data\n\tImVector<float>                 TablesLastTimeActive;       // Last used timestamp of each tables (SOA, for efficient GC)\n\tImVector<ImDrawChannel>         DrawChannelsTempMergeBuffer;\n\n\t// Tab bars\n\tImGuiTabBar* CurrentTabBar;\n\tImPool<ImGuiTabBar>             TabBars;\n\tImVector<ImGuiPtrOrIndex>       CurrentTabBarStack;\n\tImVector<ImGuiShrinkWidthItem>  ShrinkWidthBuffer;\n\n\t// Hover Delay system\n\tImGuiID                 HoverItemDelayId;\n\tImGuiID                 HoverItemDelayIdPreviousFrame;\n\tfloat                   HoverItemDelayTimer;                // Currently used by IsItemHovered()\n\tfloat                   HoverItemDelayClearTimer;           // Currently used by IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared.\n\tImGuiID                 HoverItemUnlockedStationaryId;      // Mouse has once been stationary on this item. Only reset after departing the item.\n\tImGuiID                 HoverWindowUnlockedStationaryId;    // Mouse has once been stationary on this window. Only reset after departing the window.\n\n\t// Mouse state\n\tImGuiMouseCursor        MouseCursor;\n\tfloat                   MouseStationaryTimer;               // Time the mouse has been stationary (with some loose heuristic)\n\tImVec2                  MouseLastValidPos;\n\n\t// Widget state\n\tImGuiInputTextState     InputTextState;\n\tImGuiInputTextDeactivatedState InputTextDeactivatedState;\n\tImFont                  InputTextPasswordFont;\n\tImGuiID                 TempInputId;                        // Temporary text input when CTRL+clicking on a slider, etc.\n\tImGuiColorEditFlags     ColorEditOptions;                   // Store user options for color edit widgets\n\tImGuiID                 ColorEditCurrentID;                 // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others).\n\tImGuiID                 ColorEditSavedID;                   // ID we are saving/restoring HS for\n\tfloat                   ColorEditSavedHue;                  // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips\n\tfloat                   ColorEditSavedSat;                  // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips\n\tImU32                   ColorEditSavedColor;                // RGB value with alpha set to 0.\n\tImVec4                  ColorPickerRef;                     // Initial/reference color at the time of opening the color picker.\n\tImGuiComboPreviewData   ComboPreviewData;\n\tfloat                   SliderGrabClickOffset;\n\tfloat                   SliderCurrentAccum;                 // Accumulated slider delta when using navigation controls.\n\tbool                    SliderCurrentAccumDirty;            // Has the accumulated slider delta changed since last time we tried to apply it?\n\tbool                    DragCurrentAccumDirty;\n\tfloat                   DragCurrentAccum;                   // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings\n\tfloat                   DragSpeedDefaultRatio;              // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio\n\tfloat                   ScrollbarClickDeltaToGrabCenter;    // Distance between mouse and center of grab box, normalized in parent space. Use storage?\n\tfloat                   DisabledAlphaBackup;                // Backup for style.Alpha for BeginDisabled()\n\tshort                   DisabledStackSize;\n\tshort                   LockMarkEdited;\n\tshort                   TooltipOverrideCount;\n\tImVector<char>          ClipboardHandlerData;               // If no custom clipboard handler is defined\n\tImVector<ImGuiID>       MenusIdSubmittedThisFrame;          // A list of menu IDs that were rendered at least once\n\n\t// Platform support\n\tImGuiPlatformImeData    PlatformImeData;                    // Data updated by current frame\n\tImGuiPlatformImeData    PlatformImeDataPrev;                // Previous frame data (when changing we will call io.SetPlatformImeDataFn\n\n\t// Settings\n\tbool                    SettingsLoaded;\n\tfloat                   SettingsDirtyTimer;                 // Save .ini Settings to memory when time reaches zero\n\tImGuiTextBuffer         SettingsIniData;                    // In memory .ini settings\n\tImVector<ImGuiSettingsHandler>      SettingsHandlers;       // List of .ini settings handlers\n\tImChunkStream<ImGuiWindowSettings>  SettingsWindows;        // ImGuiWindow .ini settings entries\n\tImChunkStream<ImGuiTableSettings>   SettingsTables;         // ImGuiTable .ini settings entries\n\tImVector<ImGuiContextHook>          Hooks;                  // Hooks for extensions (e.g. test engine)\n\tImGuiID                             HookIdNext;             // Next available HookId\n\n\t// Localization\n\tconst char* LocalizationTable[ImGuiLocKey_COUNT];\n\n\t// Capture/Logging\n\tbool                    LogEnabled;                         // Currently capturing\n\tImGuiLogType            LogType;                            // Capture target\n\tImFileHandle            LogFile;                            // If != NULL log to stdout/ file\n\tImGuiTextBuffer         LogBuffer;                          // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.\n\tconst char* LogNextPrefix;\n\tconst char* LogNextSuffix;\n\tfloat                   LogLinePosY;\n\tbool                    LogLineFirstItem;\n\tint                     LogDepthRef;\n\tint                     LogDepthToExpand;\n\tint                     LogDepthToExpandDefault;            // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call.\n\n\t// Debug Tools\n\tImGuiDebugLogFlags      DebugLogFlags;\n\tImGuiTextBuffer         DebugLogBuf;\n\tImGuiTextIndex          DebugLogIndex;\n\tImU8                    DebugLogClipperAutoDisableFrames;\n\tImU8                    DebugLocateFrames;                  // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above.\n\tImS8                    DebugBeginReturnValueCullDepth;     // Cycle between 0..9 then wrap around.\n\tbool                    DebugItemPickerActive;              // Item picker is active (started with DebugStartItemPicker())\n\tImU8                    DebugItemPickerMouseButton;\n\tImGuiID                 DebugItemPickerBreakId;             // Will call IM_DEBUG_BREAK() when encountering this ID\n\tImGuiMetricsConfig      DebugMetricsConfig;\n\tImGuiStackTool          DebugStackTool;\n\n\t// Misc\n\tfloat                   FramerateSecPerFrame[60];           // Calculate estimate of framerate for user over the last 60 frames..\n\tint                     FramerateSecPerFrameIdx;\n\tint                     FramerateSecPerFrameCount;\n\tfloat                   FramerateSecPerFrameAccum;\n\tint                     WantCaptureMouseNextFrame;          // Explicit capture override via SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). Default to -1.\n\tint                     WantCaptureKeyboardNextFrame;       // \"\n\tint                     WantTextInputNextFrame;\n\tImVector<char>          TempBuffer;                         // Temporary text buffer\n\n\tImGuiContext(ImFontAtlas* shared_font_atlas)\n\t{\n\t\tIO.Ctx = this;\n\t\tInputTextState.Ctx = this;\n\n\t\tInitialized = false;\n\t\tFontAtlasOwnedByContext = shared_font_atlas ? false : true;\n\t\tFont = NULL;\n\t\tFontSize = FontBaseSize = 0.0f;\n\t\tIO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();\n\t\tTime = 0.0f;\n\t\tFrameCount = 0;\n\t\tFrameCountEnded = FrameCountRendered = -1;\n\t\tWithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false;\n\t\tGcCompactAll = false;\n\t\tTestEngineHookItems = false;\n\t\tTestEngine = NULL;\n\n\t\tInputEventsNextMouseSource = ImGuiMouseSource_Mouse;\n\t\tInputEventsNextEventId = 1;\n\n\t\tWindowsActiveCount = 0;\n\t\tCurrentWindow = NULL;\n\t\tHoveredWindow = NULL;\n\t\tHoveredWindowUnderMovingWindow = NULL;\n\t\tMovingWindow = NULL;\n\t\tWheelingWindow = NULL;\n\t\tWheelingWindowStartFrame = -1;\n\t\tWheelingWindowReleaseTimer = 0.0f;\n\n\t\tDebugHookIdInfo = 0;\n\t\tHoveredId = HoveredIdPreviousFrame = 0;\n\t\tHoveredIdAllowOverlap = false;\n\t\tHoveredIdDisabled = false;\n\t\tHoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;\n\t\tActiveId = 0;\n\t\tActiveIdIsAlive = 0;\n\t\tActiveIdTimer = 0.0f;\n\t\tActiveIdIsJustActivated = false;\n\t\tActiveIdAllowOverlap = false;\n\t\tActiveIdNoClearOnFocusLoss = false;\n\t\tActiveIdHasBeenPressedBefore = false;\n\t\tActiveIdHasBeenEditedBefore = false;\n\t\tActiveIdHasBeenEditedThisFrame = false;\n\t\tActiveIdClickOffset = ImVec2(-1, -1);\n\t\tActiveIdWindow = NULL;\n\t\tActiveIdSource = ImGuiInputSource_None;\n\t\tActiveIdMouseButton = -1;\n\t\tActiveIdPreviousFrame = 0;\n\t\tActiveIdPreviousFrameIsAlive = false;\n\t\tActiveIdPreviousFrameHasBeenEditedBefore = false;\n\t\tActiveIdPreviousFrameWindow = NULL;\n\t\tLastActiveId = 0;\n\t\tLastActiveIdTimer = 0.0f;\n\n\t\tActiveIdUsingNavDirMask = 0x00;\n\t\tActiveIdUsingAllKeyboardKeys = false;\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\t\tActiveIdUsingNavInputMask = 0x00;\n#endif\n\n\t\tCurrentFocusScopeId = 0;\n\t\tCurrentItemFlags = ImGuiItemFlags_None;\n\t\tBeginMenuCount = 0;\n\n\t\tNavWindow = NULL;\n\t\tNavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;\n\t\tNavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;\n\t\tNavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;\n\t\tNavJustMovedToKeyMods = ImGuiMod_None;\n\t\tNavInputSource = ImGuiInputSource_Keyboard;\n\t\tNavLayer = ImGuiNavLayer_Main;\n\t\tNavIdIsAlive = false;\n\t\tNavMousePosDirty = false;\n\t\tNavDisableHighlight = true;\n\t\tNavDisableMouseHover = false;\n\t\tNavAnyRequest = false;\n\t\tNavInitRequest = false;\n\t\tNavInitRequestFromMove = false;\n\t\tNavMoveSubmitted = false;\n\t\tNavMoveScoringItems = false;\n\t\tNavMoveForwardToNextFrame = false;\n\t\tNavMoveFlags = ImGuiNavMoveFlags_None;\n\t\tNavMoveScrollFlags = ImGuiScrollFlags_None;\n\t\tNavMoveKeyMods = ImGuiMod_None;\n\t\tNavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None;\n\t\tNavScoringDebugCount = 0;\n\t\tNavTabbingDir = 0;\n\t\tNavTabbingCounter = 0;\n\n\t\tConfigNavWindowingKeyNext = ImGuiMod_Ctrl | ImGuiKey_Tab;\n\t\tConfigNavWindowingKeyPrev = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab;\n\t\tNavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL;\n\t\tNavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;\n\t\tNavWindowingToggleLayer = false;\n\n\t\tDimBgRatio = 0.0f;\n\n\t\tDragDropActive = DragDropWithinSource = DragDropWithinTarget = false;\n\t\tDragDropSourceFlags = ImGuiDragDropFlags_None;\n\t\tDragDropSourceFrameCount = -1;\n\t\tDragDropMouseButton = -1;\n\t\tDragDropTargetId = 0;\n\t\tDragDropAcceptFlags = ImGuiDragDropFlags_None;\n\t\tDragDropAcceptIdCurrRectSurface = 0.0f;\n\t\tDragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;\n\t\tDragDropAcceptFrameCount = -1;\n\t\tDragDropHoldJustPressedId = 0;\n\t\tmemset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));\n\n\t\tClipperTempDataStacked = 0;\n\n\t\tCurrentTable = NULL;\n\t\tTablesTempDataStacked = 0;\n\t\tCurrentTabBar = NULL;\n\n\t\tHoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0;\n\t\tHoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f;\n\n\t\tMouseCursor = ImGuiMouseCursor_Arrow;\n\t\tMouseStationaryTimer = 0.0f;\n\n\t\tTempInputId = 0;\n\t\tColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;\n\t\tColorEditCurrentID = ColorEditSavedID = 0;\n\t\tColorEditSavedHue = ColorEditSavedSat = 0.0f;\n\t\tColorEditSavedColor = 0;\n\t\tSliderGrabClickOffset = 0.0f;\n\t\tSliderCurrentAccum = 0.0f;\n\t\tSliderCurrentAccumDirty = false;\n\t\tDragCurrentAccumDirty = false;\n\t\tDragCurrentAccum = 0.0f;\n\t\tDragSpeedDefaultRatio = 1.0f / 100.0f;\n\t\tScrollbarClickDeltaToGrabCenter = 0.0f;\n\t\tDisabledAlphaBackup = 0.0f;\n\t\tDisabledStackSize = 0;\n\t\tLockMarkEdited = 0;\n\t\tTooltipOverrideCount = 0;\n\n\t\tPlatformImeData.InputPos = ImVec2(0.0f, 0.0f);\n\t\tPlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission\n\n\t\tSettingsLoaded = false;\n\t\tSettingsDirtyTimer = 0.0f;\n\t\tHookIdNext = 0;\n\n\t\tmemset(LocalizationTable, 0, sizeof(LocalizationTable));\n\n\t\tLogEnabled = false;\n\t\tLogType = ImGuiLogType_None;\n\t\tLogNextPrefix = LogNextSuffix = NULL;\n\t\tLogFile = NULL;\n\t\tLogLinePosY = FLT_MAX;\n\t\tLogLineFirstItem = false;\n\t\tLogDepthRef = 0;\n\t\tLogDepthToExpand = LogDepthToExpandDefault = 2;\n\n\t\tDebugLogFlags = ImGuiDebugLogFlags_OutputToTTY;\n\t\tDebugLocateId = 0;\n\t\tDebugLogClipperAutoDisableFrames = 0;\n\t\tDebugLocateFrames = 0;\n\t\tDebugBeginReturnValueCullDepth = -1;\n\t\tDebugItemPickerActive = false;\n\t\tDebugItemPickerMouseButton = ImGuiMouseButton_Left;\n\t\tDebugItemPickerBreakId = 0;\n\n\t\tmemset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));\n\t\tFramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0;\n\t\tFramerateSecPerFrameAccum = 0.0f;\n\t\tWantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;\n\t}\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGuiWindowTempData, ImGuiWindow\n//-----------------------------------------------------------------------------\n\n// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.\n// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..)\n// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin)\nstruct IMGUI_API ImGuiWindowTempData\n{\n\t// Layout\n\tImVec2                  CursorPos;              // Current emitting position, in absolute coordinates.\n\tImVec2                  CursorPosPrevLine;\n\tImVec2                  CursorStartPos;         // Initial position after Begin(), generally ~ window position + WindowPadding.\n\tImVec2                  CursorMaxPos;           // Used to implicitly calculate ContentSize at the beginning of next frame, for scrolling range and auto-resize. Always growing during the frame.\n\tImVec2                  IdealMaxPos;            // Used to implicitly calculate ContentSizeIdeal at the beginning of next frame, for auto-resize only. Always growing during the frame.\n\tImVec2                  CurrLineSize;\n\tImVec2                  PrevLineSize;\n\tfloat                   CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added).\n\tfloat                   PrevLineTextBaseOffset;\n\tbool                    IsSameLine;\n\tbool                    IsSetPos;\n\tImVec1                  Indent;                 // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)\n\tImVec1                  ColumnsOffset;          // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.\n\tImVec1                  GroupOffset;\n\tImVec2                  CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensate and fix the most common use case of large scroll area.\n\n\t// Keyboard/Gamepad navigation\n\tImGuiNavLayer           NavLayerCurrent;        // Current layer, 0..31 (we currently only use 0..1)\n\tshort                   NavLayersActiveMask;    // Which layers have been written to (result from previous frame)\n\tshort                   NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame)\n\tbool                    NavIsScrollPushableX;   // Set when current work location may be scrolled horizontally when moving left / right. This is generally always true UNLESS within a column.\n\tbool                    NavHideHighlightOneFrame;\n\tbool                    NavWindowHasScrollY;    // Set per window when scrolling can be used (== ScrollMax.y > 0.0f)\n\n\t// Miscellaneous\n\tbool                    MenuBarAppending;       // FIXME: Remove this\n\tImVec2                  MenuBarOffset;          // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.\n\tImGuiMenuColumns        MenuColumns;            // Simplified columns storage for menu items measurement\n\tint                     TreeDepth;              // Current tree depth.\n\tImU32                   TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.\n\tImVector<ImGuiWindow*>  ChildWindows;\n\tImGuiStorage* StateStorage;           // Current persistent per-window storage (store e.g. tree node open/close state)\n\tImGuiOldColumns* CurrentColumns;         // Current columns set\n\tint                     CurrentTableIdx;        // Current table index (into g.Tables)\n\tImGuiLayoutType         LayoutType;\n\tImGuiLayoutType         ParentLayoutType;       // Layout type of parent window at the time of Begin()\n\n\t// Local parameters stacks\n\t// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.\n\tfloat                   ItemWidth;              // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window).\n\tfloat                   TextWrapPos;            // Current text wrap pos.\n\tImVector<float>         ItemWidthStack;         // Store item widths to restore (attention: .back() is not == ItemWidth)\n\tImVector<float>         TextWrapPosStack;       // Store text wrap pos to restore (attention: .back() is not == TextWrapPos)\n};\n\n// Storage for one window\nstruct IMGUI_API ImGuiWindow\n{\n\tImGuiContext* Ctx;                                // Parent UI context (needs to be set explicitly by parent).\n\tchar* Name;                               // Window name, owned by the window.\n\tImGuiID                 ID;                                 // == ImHashStr(Name)\n\tImGuiWindowFlags        Flags;                              // See enum ImGuiWindowFlags_\n\tImGuiViewportP* Viewport;                           // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded.\n\tImVec2                  Pos;                                // Position (always rounded-up to nearest pixel)\n\tImVec2                  Size;                               // Current size (==SizeFull or collapsed title bar size)\n\tImVec2                  SizeFull;                           // Size when non collapsed\n\tImVec2                  ContentSize;                        // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding.\n\tImVec2                  ContentSizeIdeal;\n\tImVec2                  ContentSizeExplicit;                // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize().\n\tImVec2                  WindowPadding;                      // Window padding at the time of Begin().\n\tfloat                   WindowRounding;                     // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc.\n\tfloat                   WindowBorderSize;                   // Window border size at the time of Begin().\n\tfloat                   DecoOuterSizeX1, DecoOuterSizeY1;   // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin().\n\tfloat                   DecoOuterSizeX2, DecoOuterSizeY2;   // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y).\n\tfloat                   DecoInnerSizeX1, DecoInnerSizeY1;   // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes).\n\tint                     NameBufLen;                         // Size of buffer storing Name. May be larger than strlen(Name)!\n\tImGuiID                 MoveId;                             // == window->GetID(\"#MOVE\")\n\tImGuiID                 ChildId;                            // ID of corresponding item in parent window (for navigation to return from child window to parent window)\n\tImVec2                  Scroll;\n\tImVec2                  ScrollMax;\n\tImVec2                  ScrollTarget;                       // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)\n\tImVec2                  ScrollTargetCenterRatio;            // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered\n\tImVec2                  ScrollTargetEdgeSnapDist;           // 0.0f = no snapping, >0.0f snapping threshold\n\tImVec2                  ScrollbarSizes;                     // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar.\n\tbool                    ScrollbarX, ScrollbarY;             // Are scrollbars visible?\n\tbool                    Active;                             // Set to true on Begin(), unless Collapsed\n\tbool                    WasActive;\n\tbool                    WriteAccessed;                      // Set to true when any widget access the current window\n\tbool                    Collapsed;                          // Set when collapsing window to become only title-bar\n\tbool                    WantCollapseToggle;\n\tbool                    SkipItems;                          // Set when items can safely be all clipped (e.g. window not visible or collapsed)\n\tbool                    Appearing;                          // Set during the frame where the window is appearing (or re-appearing)\n\tbool                    Hidden;                             // Do not display (== HiddenFrames*** > 0)\n\tbool                    IsFallbackWindow;                   // Set on the \"Debug##Default\" window.\n\tbool                    IsExplicitChild;                    // Set when passed _ChildWindow, left to false by BeginDocked()\n\tbool                    HasCloseButton;                     // Set when the window has a close button (p_open != NULL)\n\tsigned char             ResizeBorderHeld;                   // Current border being held for resize (-1: none, otherwise 0-3)\n\tshort                   BeginCount;                         // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)\n\tshort                   BeginCountPreviousFrame;            // Number of Begin() during the previous frame\n\tshort                   BeginOrderWithinParent;             // Begin() order within immediate parent window, if we are a child window. Otherwise 0.\n\tshort                   BeginOrderWithinContext;            // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues.\n\tshort                   FocusOrder;                         // Order within WindowsFocusOrder[], altered when windows are focused.\n\tImGuiID                 PopupId;                            // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)\n\tImS8                    AutoFitFramesX, AutoFitFramesY;\n\tImS8                    AutoFitChildAxises;\n\tbool                    AutoFitOnlyGrows;\n\tImGuiDir                AutoPosLastDirection;\n\tImS8                    HiddenFramesCanSkipItems;           // Hide the window for N frames\n\tImS8                    HiddenFramesCannotSkipItems;        // Hide the window for N frames while allowing items to be submitted so we can measure their size\n\tImS8                    HiddenFramesForRenderOnly;          // Hide the window until frame N at Render() time only\n\tImS8                    DisableInputsFrames;                // Disable window interactions for N frames\n\tImGuiCond               SetWindowPosAllowFlags : 8;         // store acceptable condition flags for SetNextWindowPos() use.\n\tImGuiCond               SetWindowSizeAllowFlags : 8;        // store acceptable condition flags for SetNextWindowSize() use.\n\tImGuiCond               SetWindowCollapsedAllowFlags : 8;   // store acceptable condition flags for SetNextWindowCollapsed() use.\n\tImVec2                  SetWindowPosVal;                    // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)\n\tImVec2                  SetWindowPosPivot;                  // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right.\n\n\tImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure)\n\tImGuiWindowTempData     DC;                                 // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the \"DC\" variable name.\n\n\t// The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer.\n\t// The main 'OuterRect', omitted as a field, is window->Rect().\n\tImRect                  OuterRectClipped;                   // == Window->Rect() just after setup in Begin(). == window->Rect() for root window.\n\tImRect                  InnerRect;                          // Inner rectangle (omit title bar, menu bar, scroll bar)\n\tImRect                  InnerClipRect;                      // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect.\n\tImRect                  WorkRect;                           // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward).\n\tImRect                  ParentWorkRect;                     // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack?\n\tImRect                  ClipRect;                           // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back().\n\tImRect                  ContentRegionRect;                  // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.\n\tImVec2ih                HitTestHoleSize;                    // Define an optional rectangular hole where mouse will pass-through the window.\n\tImVec2ih                HitTestHoleOffset;\n\n\tint                     LastFrameActive;                    // Last frame number the window was Active.\n\tfloat                   LastTimeActive;                     // Last timestamp the window was Active (using float as we don't need high precision there)\n\tfloat                   ItemWidthDefault;\n\tImGuiStorage            StateStorage;\n\tImVector<ImGuiOldColumns> ColumnsStorage;\n\tfloat                   FontWindowScale;                    // User scale multiplier per-window, via SetWindowFontScale()\n\tint                     SettingsOffset;                     // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back)\n\n\tImDrawList* DrawList;                           // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)\n\tImDrawList              DrawListInst;\n\tImGuiWindow* ParentWindow;                       // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL.\n\tImGuiWindow* ParentWindowInBeginStack;\n\tImGuiWindow* RootWindow;                         // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes.\n\tImGuiWindow* RootWindowPopupTree;                // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child.\n\tImGuiWindow* RootWindowForTitleBarHighlight;     // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.\n\tImGuiWindow* RootWindowForNav;                   // Point to ourself or first ancestor which doesn't have the NavFlattened flag.\n\n\tImGuiWindow* NavLastChildNavWindow;              // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)\n\tImGuiID                 NavLastIds[ImGuiNavLayer_COUNT];    // Last known NavId for this window, per layer (0/1)\n\tImRect                  NavRectRel[ImGuiNavLayer_COUNT];    // Reference rectangle, in window relative space\n\tImVec2                  NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]; // Preferred X/Y position updated when moving on a given axis, reset to FLT_MAX.\n\tImGuiID                 NavRootFocusScopeId;                // Focus Scope ID at the time of Begin()\n\n\tint                     MemoryDrawListIdxCapacity;          // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy\n\tint                     MemoryDrawListVtxCapacity;\n\tbool                    MemoryCompacted;                    // Set when window extraneous data have been garbage collected\n\npublic:\n\tImGuiWindow(ImGuiContext* context, const char* name);\n\t~ImGuiWindow();\n\n\tImGuiID     GetID(const char* str, const char* str_end = NULL);\n\tImGuiID     GetID(const void* ptr);\n\tImGuiID     GetID(int n);\n\tImGuiID     GetIDFromRectangle(const ImRect& r_abs);\n\n\t// We don't use g.FontSize because the window may be != g.CurrentWindow.\n\tImRect      Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }\n\tfloat       CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }\n\tfloat       TitleBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }\n\tImRect      TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }\n\tfloat       MenuBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }\n\tImRect      MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Tab bar, Tab item support\n//-----------------------------------------------------------------------------\n\n// Extend ImGuiTabBarFlags_\nenum ImGuiTabBarFlagsPrivate_\n{\n\tImGuiTabBarFlags_DockNode = 1 << 20,  // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around]\n\tImGuiTabBarFlags_IsFocused = 1 << 21,\n\tImGuiTabBarFlags_SaveSettings = 1 << 22,  // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs\n};\n\n// Extend ImGuiTabItemFlags_\nenum ImGuiTabItemFlagsPrivate_\n{\n\tImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing,\n\tImGuiTabItemFlags_NoCloseButton = 1 << 20,  // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)\n\tImGuiTabItemFlags_Button = 1 << 21,  // Used by TabItemButton, change the tab item behavior to mimic a button\n};\n\n// Storage for one active tab item (sizeof() 40 bytes)\nstruct ImGuiTabItem\n{\n\tImGuiID             ID;\n\tImGuiTabItemFlags   Flags;\n\tint                 LastFrameVisible;\n\tint                 LastFrameSelected;      // This allows us to infer an ordered list of the last activated tabs with little maintenance\n\tfloat               Offset;                 // Position relative to beginning of tab\n\tfloat               Width;                  // Width currently displayed\n\tfloat               ContentWidth;           // Width of label, stored during BeginTabItem() call\n\tfloat               RequestedWidth;         // Width optionally requested by caller, -1.0f is unused\n\tImS32               NameOffset;             // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames\n\tImS16               BeginOrder;             // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable\n\tImS16               IndexDuringLayout;      // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions.\n\tbool                WantClose;              // Marked as closed by SetTabItemClosed()\n\n\tImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; }\n};\n\n// Storage for a tab bar (sizeof() 152 bytes)\nstruct IMGUI_API ImGuiTabBar\n{\n\tImVector<ImGuiTabItem> Tabs;\n\tImGuiTabBarFlags    Flags;\n\tImGuiID             ID;                     // Zero for tab-bars used by docking\n\tImGuiID             SelectedTabId;          // Selected tab/window\n\tImGuiID             NextSelectedTabId;      // Next selected tab/window. Will also trigger a scrolling animation\n\tImGuiID             VisibleTabId;           // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview)\n\tint                 CurrFrameVisible;\n\tint                 PrevFrameVisible;\n\tImRect              BarRect;\n\tfloat               CurrTabsContentsHeight;\n\tfloat               PrevTabsContentsHeight; // Record the height of contents submitted below the tab bar\n\tfloat               WidthAllTabs;           // Actual width of all tabs (locked during layout)\n\tfloat               WidthAllTabsIdeal;      // Ideal width if all tabs were visible and not clipped\n\tfloat               ScrollingAnim;\n\tfloat               ScrollingTarget;\n\tfloat               ScrollingTargetDistToVisibility;\n\tfloat               ScrollingSpeed;\n\tfloat               ScrollingRectMinX;\n\tfloat               ScrollingRectMaxX;\n\tImGuiID             ReorderRequestTabId;\n\tImS16               ReorderRequestOffset;\n\tImS8                BeginCount;\n\tbool                WantLayout;\n\tbool                VisibleTabWasSubmitted;\n\tbool                TabsAddedNew;           // Set to true when a new tab item or button has been added to the tab bar during last frame\n\tImS16               TabsActiveCount;        // Number of tabs submitted this frame.\n\tImS16               LastTabItemIdx;         // Index of last BeginTabItem() tab for use by EndTabItem()\n\tfloat               ItemSpacingY;\n\tImVec2              FramePadding;           // style.FramePadding locked at the time of BeginTabBar()\n\tImVec2              BackupCursorPos;\n\tImGuiTextBuffer     TabsNames;              // For non-docking tab bar we re-append names in a contiguous buffer.\n\n\tImGuiTabBar();\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] Table support\n//-----------------------------------------------------------------------------\n\n#define IM_COL32_DISABLE                IM_COL32(0,0,0,1)   // Special sentinel code which cannot be used as a regular color.\n#define IMGUI_TABLE_MAX_COLUMNS         512                 // May be further lifted\n\n// Our current column maximum is 64 but we may raise that in the future.\ntypedef ImS16 ImGuiTableColumnIdx;\ntypedef ImU16 ImGuiTableDrawChannelIdx;\n\n// [Internal] sizeof() ~ 112\n// We use the terminology \"Enabled\" to refer to a column that is not Hidden by user/api.\n// We use the terminology \"Clipped\" to refer to a column that is out of sight because of scrolling/clipping.\n// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use \"Visible\" to mean \"not clipped\".\nstruct ImGuiTableColumn\n{\n\tImGuiTableColumnFlags   Flags;                          // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_\n\tfloat                   WidthGiven;                     // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space.\n\tfloat                   MinX;                           // Absolute positions\n\tfloat                   MaxX;\n\tfloat                   WidthRequest;                   // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout()\n\tfloat                   WidthAuto;                      // Automatic width\n\tfloat                   StretchWeight;                  // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.\n\tfloat                   InitStretchWeightOrWidth;       // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).\n\tImRect                  ClipRect;                       // Clipping rectangle for the column\n\tImGuiID                 UserID;                         // Optional, value passed to TableSetupColumn()\n\tfloat                   WorkMinX;                       // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column\n\tfloat                   WorkMaxX;                       // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2)\n\tfloat                   ItemWidth;                      // Current item width for the column, preserved across rows\n\tfloat                   ContentMaxXFrozen;              // Contents maximum position for frozen rows (apart from headers), from which we can infer content width.\n\tfloat                   ContentMaxXUnfrozen;\n\tfloat                   ContentMaxXHeadersUsed;         // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls\n\tfloat                   ContentMaxXHeadersIdeal;\n\tImS16                   NameOffset;                     // Offset into parent ColumnsNames[]\n\tImGuiTableColumnIdx     DisplayOrder;                   // Index within Table's IndexToDisplayOrder[] (column may be reordered by users)\n\tImGuiTableColumnIdx     IndexWithinEnabledSet;          // Index within enabled/visible set (<= IndexToDisplayOrder)\n\tImGuiTableColumnIdx     PrevEnabledColumn;              // Index of prev enabled/visible column within Columns[], -1 if first enabled/visible column\n\tImGuiTableColumnIdx     NextEnabledColumn;              // Index of next enabled/visible column within Columns[], -1 if last enabled/visible column\n\tImGuiTableColumnIdx     SortOrder;                      // Index of this column within sort specs, -1 if not sorting on this column, 0 for single-sort, may be >0 on multi-sort\n\tImGuiTableDrawChannelIdx DrawChannelCurrent;            // Index within DrawSplitter.Channels[]\n\tImGuiTableDrawChannelIdx DrawChannelFrozen;             // Draw channels for frozen rows (often headers)\n\tImGuiTableDrawChannelIdx DrawChannelUnfrozen;           // Draw channels for unfrozen rows\n\tbool                    IsEnabled;                      // IsUserEnabled && (Flags & ImGuiTableColumnFlags_Disabled) == 0\n\tbool                    IsUserEnabled;                  // Is the column not marked Hidden by the user? (unrelated to being off view, e.g. clipped by scrolling).\n\tbool                    IsUserEnabledNextFrame;\n\tbool                    IsVisibleX;                     // Is actually in view (e.g. overlapping the host window clipping rectangle, not scrolled).\n\tbool                    IsVisibleY;\n\tbool                    IsRequestOutput;                // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not.\n\tbool                    IsSkipItems;                    // Do we want item submissions to this column to be completely ignored (no layout will happen).\n\tbool                    IsPreserveWidthAuto;\n\tImS8                    NavLayerCurrent;                // ImGuiNavLayer in 1 byte\n\tImU8                    AutoFitQueue;                   // Queue of 8 values for the next 8 frames to request auto-fit\n\tImU8                    CannotSkipItemsQueue;           // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem\n\tImU8                    SortDirection : 2;              // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending\n\tImU8                    SortDirectionsAvailCount : 2;   // Number of available sort directions (0 to 3)\n\tImU8                    SortDirectionsAvailMask : 4;    // Mask of available sort directions (1-bit each)\n\tImU8                    SortDirectionsAvailList;        // Ordered list of available sort directions (2-bits each, total 8-bits)\n\n\tImGuiTableColumn()\n\t{\n\t\tmemset(this, 0, sizeof(*this));\n\t\tStretchWeight = WidthRequest = -1.0f;\n\t\tNameOffset = -1;\n\t\tDisplayOrder = IndexWithinEnabledSet = -1;\n\t\tPrevEnabledColumn = NextEnabledColumn = -1;\n\t\tSortOrder = -1;\n\t\tSortDirection = ImGuiSortDirection_None;\n\t\tDrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1;\n\t}\n};\n\n// Transient cell data stored per row.\n// sizeof() ~ 6\nstruct ImGuiTableCellData\n{\n\tImU32                       BgColor;    // Actual color\n\tImGuiTableColumnIdx         Column;     // Column number\n};\n\n// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?)\nstruct ImGuiTableInstanceData\n{\n\tImGuiID                     TableInstanceID;\n\tfloat                       LastOuterHeight;            // Outer height from last frame\n\tfloat                       LastFirstRowHeight;         // Height of first row from last frame (FIXME: this is used as \"header height\" and may be reworked)\n\tfloat                       LastFrozenHeight;           // Height of frozen section from last frame\n\tint                         HoveredRowLast;             // Index of row which was hovered last frame.\n\tint                         HoveredRowNext;             // Index of row hovered this frame, set after encountering it.\n\n\tImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; HoveredRowLast = HoveredRowNext = -1; }\n};\n\n// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData\n// sizeof() ~ 580 bytes + heap allocs described in TableBeginInitMemory()\nstruct IMGUI_API ImGuiTable\n{\n\tImGuiID                     ID;\n\tImGuiTableFlags             Flags;\n\tvoid* RawData;                    // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[]\n\tImGuiTableTempData* TempData;                   // Transient data while table is active. Point within g.CurrentTableStack[]\n\tImSpan<ImGuiTableColumn>    Columns;                    // Point within RawData[]\n\tImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex;        // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)\n\tImSpan<ImGuiTableCellData>  RowCellData;                // Point within RawData[]. Store cells background requests for current row.\n\tImBitArrayPtr               EnabledMaskByDisplayOrder;  // Column DisplayOrder -> IsEnabled map\n\tImBitArrayPtr               EnabledMaskByIndex;         // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data\n\tImBitArrayPtr               VisibleMaskByIndex;         // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)\n\tImGuiTableFlags             SettingsLoadedFlags;        // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)\n\tint                         SettingsOffset;             // Offset in g.SettingsTables\n\tint                         LastFrameActive;\n\tint                         ColumnsCount;               // Number of columns declared in BeginTable()\n\tint                         CurrentRow;\n\tint                         CurrentColumn;\n\tImS16                       InstanceCurrent;            // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched.\n\tImS16                       InstanceInteracted;         // Mark which instance (generally 0) of the same ID is being interacted with\n\tfloat                       RowPosY1;\n\tfloat                       RowPosY2;\n\tfloat                       RowMinHeight;               // Height submitted to TableNextRow()\n\tfloat                       RowCellPaddingY;            // Top and bottom padding. Reloaded during row change.\n\tfloat                       RowTextBaseline;\n\tfloat                       RowIndentOffsetX;\n\tImGuiTableRowFlags          RowFlags : 16;              // Current row flags, see ImGuiTableRowFlags_\n\tImGuiTableRowFlags          LastRowFlags : 16;\n\tint                         RowBgColorCounter;          // Counter for alternating background colors (can be fast-forwarded by e.g clipper), not same as CurrentRow because header rows typically don't increase this.\n\tImU32                       RowBgColor[2];              // Background color override for current row.\n\tImU32                       BorderColorStrong;\n\tImU32                       BorderColorLight;\n\tfloat                       BorderX1;\n\tfloat                       BorderX2;\n\tfloat                       HostIndentX;\n\tfloat                       MinColumnWidth;\n\tfloat                       OuterPaddingX;\n\tfloat                       CellPaddingX;               // Padding from each borders. Locked in BeginTable()/Layout.\n\tfloat                       CellSpacingX1;              // Spacing between non-bordered cells. Locked in BeginTable()/Layout.\n\tfloat                       CellSpacingX2;\n\tfloat                       InnerWidth;                 // User value passed to BeginTable(), see comments at the top of BeginTable() for details.\n\tfloat                       ColumnsGivenWidth;          // Sum of current column width\n\tfloat                       ColumnsAutoFitWidth;        // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window\n\tfloat                       ColumnsStretchSumWeights;   // Sum of weight of all enabled stretching columns\n\tfloat                       ResizedColumnNextWidth;\n\tfloat                       ResizeLockMinContentsX2;    // Lock minimum contents width while resizing down in order to not create feedback loops. But we allow growing the table.\n\tfloat                       RefScale;                   // Reference scale to be able to rescale columns on font/dpi changes.\n\tImRect                      OuterRect;                  // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().\n\tImRect                      InnerRect;                  // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is\n\tImRect                      WorkRect;\n\tImRect                      InnerClipRect;\n\tImRect                      BgClipRect;                 // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries\n\tImRect                      Bg0ClipRectForDrawCmd;      // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped\n\tImRect                      Bg2ClipRectForDrawCmd;      // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect.\n\tImRect                      HostClipRect;               // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.\n\tImRect                      HostBackupInnerClipRect;    // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground()\n\tImGuiWindow* OuterWindow;                // Parent window for the table\n\tImGuiWindow* InnerWindow;                // Window holding the table data (== OuterWindow or a child window)\n\tImGuiTextBuffer             ColumnsNames;               // Contiguous buffer holding columns names\n\tImDrawListSplitter* DrawSplitter;               // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly\n\tImGuiTableInstanceData      InstanceDataFirst;\n\tImVector<ImGuiTableInstanceData>    InstanceDataExtra;  // FIXME-OPT: Using a small-vector pattern would be good.\n\tImGuiTableColumnSortSpecs   SortSpecsSingle;\n\tImVector<ImGuiTableColumnSortSpecs> SortSpecsMulti;     // FIXME-OPT: Using a small-vector pattern would be good.\n\tImGuiTableSortSpecs         SortSpecs;                  // Public facing sorts specs, this is what we return in TableGetSortSpecs()\n\tImGuiTableColumnIdx         SortSpecsCount;\n\tImGuiTableColumnIdx         ColumnsEnabledCount;        // Number of enabled columns (<= ColumnsCount)\n\tImGuiTableColumnIdx         ColumnsEnabledFixedCount;   // Number of enabled columns (<= ColumnsCount)\n\tImGuiTableColumnIdx         DeclColumnsCount;           // Count calls to TableSetupColumn()\n\tImGuiTableColumnIdx         HoveredColumnBody;          // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column!\n\tImGuiTableColumnIdx         HoveredColumnBorder;        // Index of column whose right-border is being hovered (for resizing).\n\tImGuiTableColumnIdx         AutoFitSingleColumn;        // Index of single column requesting auto-fit.\n\tImGuiTableColumnIdx         ResizedColumn;              // Index of column being resized. Reset when InstanceCurrent==0.\n\tImGuiTableColumnIdx         LastResizedColumn;          // Index of column being resized from previous frame.\n\tImGuiTableColumnIdx         HeldHeaderColumn;           // Index of column header being held.\n\tImGuiTableColumnIdx         ReorderColumn;              // Index of column being reordered. (not cleared)\n\tImGuiTableColumnIdx         ReorderColumnDir;           // -1 or +1\n\tImGuiTableColumnIdx         LeftMostEnabledColumn;      // Index of left-most non-hidden column.\n\tImGuiTableColumnIdx         RightMostEnabledColumn;     // Index of right-most non-hidden column.\n\tImGuiTableColumnIdx         LeftMostStretchedColumn;    // Index of left-most stretched column.\n\tImGuiTableColumnIdx         RightMostStretchedColumn;   // Index of right-most stretched column.\n\tImGuiTableColumnIdx         ContextPopupColumn;         // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot\n\tImGuiTableColumnIdx         FreezeRowsRequest;          // Requested frozen rows count\n\tImGuiTableColumnIdx         FreezeRowsCount;            // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset)\n\tImGuiTableColumnIdx         FreezeColumnsRequest;       // Requested frozen columns count\n\tImGuiTableColumnIdx         FreezeColumnsCount;         // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset)\n\tImGuiTableColumnIdx         RowCellDataCurrent;         // Index of current RowCellData[] entry in current row\n\tImGuiTableDrawChannelIdx    DummyDrawChannel;           // Redirect non-visible columns here.\n\tImGuiTableDrawChannelIdx    Bg2DrawChannelCurrent;      // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[]\n\tImGuiTableDrawChannelIdx    Bg2DrawChannelUnfrozen;\n\tbool                        IsLayoutLocked;             // Set by TableUpdateLayout() which is called when beginning the first row.\n\tbool                        IsInsideRow;                // Set when inside TableBeginRow()/TableEndRow().\n\tbool                        IsInitializing;\n\tbool                        IsSortSpecsDirty;\n\tbool                        IsUsingHeaders;             // Set when the first row had the ImGuiTableRowFlags_Headers flag.\n\tbool                        IsContextPopupOpen;         // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted).\n\tbool                        IsSettingsRequestLoad;\n\tbool                        IsSettingsDirty;            // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data.\n\tbool                        IsDefaultDisplayOrder;      // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)\n\tbool                        IsResetAllRequest;\n\tbool                        IsResetDisplayOrderRequest;\n\tbool                        IsUnfrozenRows;             // Set when we got past the frozen row.\n\tbool                        IsDefaultSizingPolicy;      // Set if user didn't explicitly set a sizing policy in BeginTable()\n\tbool                        HasScrollbarYCurr;          // Whether ANY instance of this table had a vertical scrollbar during the current frame.\n\tbool                        HasScrollbarYPrev;          // Whether ANY instance of this table had a vertical scrollbar during the previous.\n\tbool                        MemoryCompacted;\n\tbool                        HostSkipItems;              // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis\n\n\tImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; }\n\t~ImGuiTable() { IM_FREE(RawData); }\n};\n\n// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table).\n// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure.\n// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics.\n// sizeof() ~ 112 bytes.\nstruct IMGUI_API ImGuiTableTempData\n{\n\tint                         TableIndex;                 // Index in g.Tables.Buf[] pool\n\tfloat                       LastTimeActive;             // Last timestamp this structure was used\n\n\tImVec2                      UserOuterSize;              // outer_size.x passed to BeginTable()\n\tImDrawListSplitter          DrawSplitter;\n\n\tImRect                      HostBackupWorkRect;         // Backup of InnerWindow->WorkRect at the end of BeginTable()\n\tImRect                      HostBackupParentWorkRect;   // Backup of InnerWindow->ParentWorkRect at the end of BeginTable()\n\tImVec2                      HostBackupPrevLineSize;     // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable()\n\tImVec2                      HostBackupCurrLineSize;     // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable()\n\tImVec2                      HostBackupCursorMaxPos;     // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable()\n\tImVec1                      HostBackupColumnsOffset;    // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable()\n\tfloat                       HostBackupItemWidth;        // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable()\n\tint                         HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable()\n\n\tImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; }\n};\n\n// sizeof() ~ 12\nstruct ImGuiTableColumnSettings\n{\n\tfloat                   WidthOrWeight;\n\tImGuiID                 UserID;\n\tImGuiTableColumnIdx     Index;\n\tImGuiTableColumnIdx     DisplayOrder;\n\tImGuiTableColumnIdx     SortOrder;\n\tImU8                    SortDirection : 2;\n\tImU8                    IsEnabled : 1; // \"Visible\" in ini file\n\tImU8                    IsStretch : 1;\n\n\tImGuiTableColumnSettings()\n\t{\n\t\tWidthOrWeight = 0.0f;\n\t\tUserID = 0;\n\t\tIndex = -1;\n\t\tDisplayOrder = SortOrder = -1;\n\t\tSortDirection = ImGuiSortDirection_None;\n\t\tIsEnabled = 1;\n\t\tIsStretch = 0;\n\t}\n};\n\n// This is designed to be stored in a single ImChunkStream (1 header followed by N ImGuiTableColumnSettings, etc.)\nstruct ImGuiTableSettings\n{\n\tImGuiID                     ID;                     // Set to 0 to invalidate/delete the setting\n\tImGuiTableFlags             SaveFlags;              // Indicate data we want to save using the Resizable/Reorderable/Sortable/Hideable flags (could be using its own flags..)\n\tfloat                       RefScale;               // Reference scale to be able to rescale columns on font/dpi changes.\n\tImGuiTableColumnIdx         ColumnsCount;\n\tImGuiTableColumnIdx         ColumnsCountMax;        // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher\n\tbool                        WantApply;              // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)\n\n\tImGuiTableSettings() { memset(this, 0, sizeof(*this)); }\n\tImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); }\n};\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImGui internal API\n// No guarantee of forward compatibility here!\n//-----------------------------------------------------------------------------\n\nnamespace ImGui\n{\n\t// Windows\n\t// We should always have a CurrentWindow in the stack (there is an implicit \"Debug\" window)\n\t// If this ever crash because g.CurrentWindow is NULL it means that either\n\t// - ImGui::NewFrame() has never been called, which is illegal.\n\t// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.\n\tinline    ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }\n\tinline    ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }\n\tIMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);\n\tIMGUI_API ImGuiWindow* FindWindowByName(const char* name);\n\tIMGUI_API void          UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);\n\tIMGUI_API ImVec2        CalcWindowNextAutoFitSize(ImGuiWindow* window);\n\tIMGUI_API bool          IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy);\n\tIMGUI_API bool          IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent);\n\tIMGUI_API bool          IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below);\n\tIMGUI_API bool          IsWindowNavFocusable(ImGuiWindow* window);\n\tIMGUI_API void          SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);\n\tIMGUI_API void          SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);\n\tIMGUI_API void          SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);\n\tIMGUI_API void          SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size);\n\tIMGUI_API void          SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window);\n\tinline ImRect           WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); }\n\tinline ImRect           WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); }\n\tinline ImVec2           WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); }\n\n\t// Windows: Display Order and Focus Order\n\tIMGUI_API void          FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0);\n\tIMGUI_API void          FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags);\n\tIMGUI_API void          BringWindowToFocusFront(ImGuiWindow* window);\n\tIMGUI_API void          BringWindowToDisplayFront(ImGuiWindow* window);\n\tIMGUI_API void          BringWindowToDisplayBack(ImGuiWindow* window);\n\tIMGUI_API void          BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* above_window);\n\tIMGUI_API int           FindWindowDisplayIndex(ImGuiWindow* window);\n\tIMGUI_API ImGuiWindow* FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window);\n\n\t// Fonts, drawing\n\tIMGUI_API void          SetCurrentFont(ImFont* font);\n\tinline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }\n\tinline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.\n\tIMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport);                     // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.\n\tIMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport);                     // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.\n\tIMGUI_API void          AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);\n\n\t// Init\n\tIMGUI_API void          Initialize();\n\tIMGUI_API void          Shutdown();    // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext().\n\n\t// NewFrame\n\tIMGUI_API void          UpdateInputEvents(bool trickle_fast_inputs);\n\tIMGUI_API void          UpdateHoveredWindowAndCaptureFlags();\n\tIMGUI_API void          StartMouseMovingWindow(ImGuiWindow* window);\n\tIMGUI_API void          UpdateMouseMovingWindowNewFrame();\n\tIMGUI_API void          UpdateMouseMovingWindowEndFrame();\n\n\t// Generic context hooks\n\tIMGUI_API ImGuiID       AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook);\n\tIMGUI_API void          RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove);\n\tIMGUI_API void          CallContextHooks(ImGuiContext* context, ImGuiContextHookType type);\n\n\t// Viewports\n\tIMGUI_API void          SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport);\n\n\t// Settings\n\tIMGUI_API void                  MarkIniSettingsDirty();\n\tIMGUI_API void                  MarkIniSettingsDirty(ImGuiWindow* window);\n\tIMGUI_API void                  ClearIniSettings();\n\tIMGUI_API void                  AddSettingsHandler(const ImGuiSettingsHandler* handler);\n\tIMGUI_API void                  RemoveSettingsHandler(const char* type_name);\n\tIMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);\n\n\t// Settings - Windows\n\tIMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name);\n\tIMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id);\n\tIMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window);\n\tIMGUI_API void                  ClearWindowSettings(const char* name);\n\n\t// Localization\n\tIMGUI_API void          LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count);\n\tinline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : \"*Missing Text*\"; }\n\n\t// Scrolling\n\tIMGUI_API void          SetScrollX(ImGuiWindow* window, float scroll_x);\n\tIMGUI_API void          SetScrollY(ImGuiWindow* window, float scroll_y);\n\tIMGUI_API void          SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio);\n\tIMGUI_API void          SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio);\n\n\t// Early work-in-progress API (ScrollToItem() will become public)\n\tIMGUI_API void          ScrollToItem(ImGuiScrollFlags flags = 0);\n\tIMGUI_API void          ScrollToRect(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0);\n\tIMGUI_API ImVec2        ScrollToRectEx(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0);\n\t//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tinline void             ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& rect) { ScrollToRect(window, rect, ImGuiScrollFlags_KeepVisibleEdgeY); }\n\t//#endif\n\n\t\t// Basic Accessors\n\tinline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; }\n\tinline ImGuiItemFlags   GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; }\n\tinline ImGuiID          GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; }\n\tinline ImGuiID          GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; }\n\tIMGUI_API void          SetActiveID(ImGuiID id, ImGuiWindow* window);\n\tIMGUI_API void          SetFocusID(ImGuiID id, ImGuiWindow* window);\n\tIMGUI_API void          ClearActiveID();\n\tIMGUI_API ImGuiID       GetHoveredID();\n\tIMGUI_API void          SetHoveredID(ImGuiID id);\n\tIMGUI_API void          KeepAliveID(ImGuiID id);\n\tIMGUI_API void          MarkItemEdited(ImGuiID id);     // Mark data associated to given item as \"edited\", used by IsItemDeactivatedAfterEdit() function.\n\tIMGUI_API void          PushOverrideID(ImGuiID id);     // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes)\n\tIMGUI_API ImGuiID       GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed);\n\tIMGUI_API ImGuiID       GetIDWithSeed(int n, ImGuiID seed);\n\n\t// Basic Helpers for widget code\n\tIMGUI_API void          ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);\n\tinline void             ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min.\n\tIMGUI_API bool          ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0);\n\tIMGUI_API bool          ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags);\n\tIMGUI_API bool          IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0);\n\tIMGUI_API bool          IsClippedEx(const ImRect& bb, ImGuiID id);\n\tIMGUI_API void          SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);\n\tIMGUI_API ImVec2        CalcItemSize(ImVec2 size, float default_w, float default_h);\n\tIMGUI_API float         CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);\n\tIMGUI_API void          PushMultiItemsWidths(int components, float width_full);\n\tIMGUI_API bool          IsItemToggledSelection();                                   // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)\n\tIMGUI_API ImVec2        GetContentRegionMaxAbs();\n\tIMGUI_API void          ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);\n\n\t// Parameter stacks (shared)\n\tIMGUI_API void          PushItemFlag(ImGuiItemFlags option, bool enabled);\n\tIMGUI_API void          PopItemFlag();\n\tIMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);\n\n\t// Logging/Capture\n\tIMGUI_API void          LogBegin(ImGuiLogType type, int auto_open_depth);           // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name.\n\tIMGUI_API void          LogToBuffer(int auto_open_depth = -1);                      // Start logging/capturing to internal buffer\n\tIMGUI_API void          LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL);\n\tIMGUI_API void          LogSetNextTextDecoration(const char* prefix, const char* suffix);\n\n\t// Popups, Modals, Tooltips\n\tIMGUI_API bool          BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags);\n\tIMGUI_API void          OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);\n\tIMGUI_API void          ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);\n\tIMGUI_API void          ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);\n\tIMGUI_API void          ClosePopupsExceptModals();\n\tIMGUI_API bool          IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);\n\tIMGUI_API bool          BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);\n\tIMGUI_API bool          BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);\n\tIMGUI_API ImRect        GetPopupAllowedExtentRect(ImGuiWindow* window);\n\tIMGUI_API ImGuiWindow* GetTopMostPopupModal();\n\tIMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal();\n\tIMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window);\n\tIMGUI_API ImVec2        FindBestWindowPosForPopup(ImGuiWindow* window);\n\tIMGUI_API ImVec2        FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);\n\n\t// Menus\n\tIMGUI_API bool          BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);\n\tIMGUI_API bool          BeginMenuEx(const char* label, const char* icon, bool enabled = true);\n\tIMGUI_API bool          MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true);\n\n\t// Combos\n\tIMGUI_API bool          BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags);\n\tIMGUI_API bool          BeginComboPreview();\n\tIMGUI_API void          EndComboPreview();\n\n\t// Gamepad/Keyboard Navigation\n\tIMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit);\n\tIMGUI_API void          NavInitRequestApplyResult();\n\tIMGUI_API bool          NavMoveRequestButNoResultYet();\n\tIMGUI_API void          NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);\n\tIMGUI_API void          NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);\n\tIMGUI_API void          NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result);\n\tIMGUI_API void          NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data);\n\tIMGUI_API void          NavMoveRequestCancel();\n\tIMGUI_API void          NavMoveRequestApplyResult();\n\tIMGUI_API void          NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);\n\tIMGUI_API void          NavClearPreferredPosForAxis(ImGuiAxis axis);\n\tIMGUI_API void          NavUpdateCurrentWindowIsScrollPushableX();\n\tIMGUI_API void          SetNavWindow(ImGuiWindow* window);\n\tIMGUI_API void          SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel);\n\n\t// Focus/Activation\n\t// This should be part of a larger set of API: FocusItem(offset = -1), FocusItemByID(id), ActivateItem(offset = -1), ActivateItemByID(id) etc. which are\n\t// much harder to design and implement than expected. I have a couple of private branches on this matter but it's not simple. For now implementing the easy ones.\n\tIMGUI_API void          FocusItem();                    // Focus last item (no selection/activation).\n\tIMGUI_API void          ActivateItemByID(ImGuiID id);   // Activate an item by ID (button, checkbox, tree node etc.). Activation is queued and processed on the next frame when the item is encountered again.\n\n\t// Inputs\n\t// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.\n\tinline bool             IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; }\n\tinline bool             IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; }\n\tinline bool             IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; }\n\tinline bool             IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; }\n\tinline bool             IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; }\n\tinline bool             IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; }\n\tinline bool             IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; }\n\tinline ImGuiKeyChord    ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); }\n\tinline ImGuiKey         ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key)\n\t{\n\t\tImGuiContext& g = *ctx;\n\t\tif (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl;\n\t\tif (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift;\n\t\tif (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt;\n\t\tif (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper;\n\t\tif (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl);\n\t\treturn key;\n\t}\n\n\tIMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key);\n\tinline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); }\n\tIMGUI_API void          GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size);\n\tinline ImGuiKey         MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); }\n\tIMGUI_API bool          IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f);\n\tIMGUI_API ImVec2        GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down);\n\tIMGUI_API float         GetNavTweakPressedAmount(ImGuiAxis axis);\n\tIMGUI_API int           CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate);\n\tIMGUI_API void          GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate);\n\tIMGUI_API void          SetActiveIdUsingAllKeyboardKeys();\n\tinline bool             IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }\n\n\t// [EXPERIMENTAL] Low-Level: Key/Input Ownership\n\t// - The idea is that instead of \"eating\" a given input, we can link to an owner id.\n\t// - Ownership is most often claimed as a result of reacting to a press/down event (but occasionally may be claimed ahead).\n\t// - Input queries can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID.\n\t// - Legacy input queries (without specifying an owner or _Any or _None) are equivalent to using ImGuiKeyOwner_Any (== 0).\n\t// - Input ownership is automatically released on the frame after a key is released. Therefore:\n\t//   - for ownership registration happening as a result of a down/press event, the SetKeyOwner() call may be done once (common case).\n\t//   - for ownership registration happening ahead of a down/press event, the SetKeyOwner() call needs to be made every frame (happens if e.g. claiming ownership on hover).\n\t// - SetItemKeyOwner() is a shortcut for common simple case. A custom widget will probably want to call SetKeyOwner() multiple times directly based on its interaction state.\n\t// - This is marked experimental because not all widgets are fully honoring the Set/Test idioms. We will need to move forward step by step.\n\t//   Please open a GitHub Issue to submit your usage scenario or if there's a use case you need solved.\n\tIMGUI_API ImGuiID           GetKeyOwner(ImGuiKey key);\n\tIMGUI_API void              SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);\n\tIMGUI_API void              SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0);\n\tIMGUI_API void              SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0);           // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.\n\tIMGUI_API bool              TestKeyOwner(ImGuiKey key, ImGuiID owner_id);                       // Test that key is either not owned, either owned by 'owner_id'\n\tinline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; }\n\n\t// [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership\n\t// - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag.\n\t// - Expected to be later promoted to public API, the prototypes are designed to replace existing ones (since owner_id can default to Any == 0)\n\t// - Specifying a value for 'ImGuiID owner' will test that EITHER the key is NOT owned (UNLESS locked), EITHER the key is owned by 'owner'.\n\t//   Legacy functions use ImGuiKeyOwner_Any meaning that they typically ignore ownership, unless a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease.\n\t// - Binding generators may want to ignore those for now, or suffix them with Ex() until we decide if this gets moved into public API.\n\tIMGUI_API bool              IsKeyDown(ImGuiKey key, ImGuiID owner_id);\n\tIMGUI_API bool              IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);    // Important: when transitioning from old to new IsKeyPressed(): old API has \"bool repeat = true\", so would default to repeat. New API requiress explicit ImGuiInputFlags_Repeat.\n\tIMGUI_API bool              IsKeyReleased(ImGuiKey key, ImGuiID owner_id);\n\tIMGUI_API bool              IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id);\n\tIMGUI_API bool              IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0);\n\tIMGUI_API bool              IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id);\n\n\t// [EXPERIMENTAL] Shortcut Routing\n\t// - ImGuiKeyChord = a ImGuiKey optionally OR-red with ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super.\n\t//     ImGuiKey_C                 (accepted by functions taking ImGuiKey or ImGuiKeyChord)\n\t//     ImGuiKey_C | ImGuiMod_Ctrl (accepted by functions taking ImGuiKeyChord)\n\t//   ONLY ImGuiMod_XXX values are legal to 'OR' with an ImGuiKey. You CANNOT 'OR' two ImGuiKey values.\n\t// - When using one of the routing flags (e.g. ImGuiInputFlags_RouteFocused): routes requested ahead of time given a chord (key + modifiers) and a routing policy.\n\t// - Routes are resolved during NewFrame(): if keyboard modifiers are matching current ones: SetKeyOwner() is called + route is granted for the frame.\n\t// - Route is granted to a single owner. When multiple requests are made we have policies to select the winning route.\n\t// - Multiple read sites may use the same owner id and will all get the granted route.\n\t// - For routing: when owner_id is 0 we use the current Focus Scope ID as a default owner in order to identify our location.\n\tIMGUI_API bool              Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);\n\tIMGUI_API bool              SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);\n\tIMGUI_API bool              TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id);\n\tIMGUI_API ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord);\n\n\t// [EXPERIMENTAL] Focus Scope\n\t// This is generally used to identify a unique input location (for e.g. a selection set)\n\t// There is one per window (automatically set in Begin), but:\n\t// - Selection patterns generally need to react (e.g. clear a selection) when landing on one item of the set.\n\t//   So in order to identify a set multiple lists in same window may each need a focus scope.\n\t//   If you imagine an hypothetical BeginSelectionGroup()/EndSelectionGroup() api, it would likely call PushFocusScope()/EndFocusScope()\n\t// - Shortcut routing also use focus scope as a default location identifier if an owner is not provided.\n\t// We don't use the ID Stack for this as it is common to want them separate.\n\tIMGUI_API void          PushFocusScope(ImGuiID id);\n\tIMGUI_API void          PopFocusScope();\n\tinline ImGuiID          GetCurrentFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentFocusScopeId; }   // Focus scope we are outputting into, set by PushFocusScope()\n\n\t// Drag and Drop\n\tIMGUI_API bool          IsDragDropActive();\n\tIMGUI_API bool          BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);\n\tIMGUI_API void          ClearDragDrop();\n\tIMGUI_API bool          IsDragDropPayloadBeingAccepted();\n\tIMGUI_API void          RenderDragDropTargetRect(const ImRect& bb);\n\n\t// Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)\n\tIMGUI_API void          SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);\n\tIMGUI_API void          BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().\n\tIMGUI_API void          EndColumns();                                                               // close columns\n\tIMGUI_API void          PushColumnClipRect(int column_index);\n\tIMGUI_API void          PushColumnsBackground();\n\tIMGUI_API void          PopColumnsBackground();\n\tIMGUI_API ImGuiID       GetColumnsID(const char* str_id, int count);\n\tIMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);\n\tIMGUI_API float         GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm);\n\tIMGUI_API float         GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset);\n\n\t// Tables: Candidates for public API\n\tIMGUI_API void          TableOpenContextMenu(int column_n = -1);\n\tIMGUI_API void          TableSetColumnWidth(int column_n, float width);\n\tIMGUI_API void          TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);\n\tIMGUI_API int           TableGetHoveredColumn();    // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.\n\tIMGUI_API int           TableGetHoveredRow();       // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet.\n\tIMGUI_API float         TableGetHeaderRowHeight();\n\tIMGUI_API void          TablePushBackgroundChannel();\n\tIMGUI_API void          TablePopBackgroundChannel();\n\n\t// Tables: Internals\n\tinline    ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; }\n\tIMGUI_API ImGuiTable* TableFindByID(ImGuiID id);\n\tIMGUI_API bool          BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);\n\tIMGUI_API void          TableBeginInitMemory(ImGuiTable* table, int columns_count);\n\tIMGUI_API void          TableBeginApplyRequests(ImGuiTable* table);\n\tIMGUI_API void          TableSetupDrawChannels(ImGuiTable* table);\n\tIMGUI_API void          TableUpdateLayout(ImGuiTable* table);\n\tIMGUI_API void          TableUpdateBorders(ImGuiTable* table);\n\tIMGUI_API void          TableUpdateColumnsWeightFromWidth(ImGuiTable* table);\n\tIMGUI_API void          TableDrawBorders(ImGuiTable* table);\n\tIMGUI_API void          TableDrawContextMenu(ImGuiTable* table);\n\tIMGUI_API bool          TableBeginContextMenuPopup(ImGuiTable* table);\n\tIMGUI_API void          TableMergeDrawChannels(ImGuiTable* table);\n\tinline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }\n\tinline ImGuiID                  TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; }\n\tIMGUI_API void          TableSortSpecsSanitize(ImGuiTable* table);\n\tIMGUI_API void          TableSortSpecsBuild(ImGuiTable* table);\n\tIMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);\n\tIMGUI_API void          TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column);\n\tIMGUI_API float         TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column);\n\tIMGUI_API void          TableBeginRow(ImGuiTable* table);\n\tIMGUI_API void          TableEndRow(ImGuiTable* table);\n\tIMGUI_API void          TableBeginCell(ImGuiTable* table, int column_n);\n\tIMGUI_API void          TableEndCell(ImGuiTable* table);\n\tIMGUI_API ImRect        TableGetCellBgRect(const ImGuiTable* table, int column_n);\n\tIMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);\n\tIMGUI_API ImGuiID       TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);\n\tIMGUI_API float         TableGetMaxColumnWidth(const ImGuiTable* table, int column_n);\n\tIMGUI_API void          TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);\n\tIMGUI_API void          TableSetColumnWidthAutoAll(ImGuiTable* table);\n\tIMGUI_API void          TableRemove(ImGuiTable* table);\n\tIMGUI_API void          TableGcCompactTransientBuffers(ImGuiTable* table);\n\tIMGUI_API void          TableGcCompactTransientBuffers(ImGuiTableTempData* table);\n\tIMGUI_API void          TableGcCompactSettings();\n\n\t// Tables: Settings\n\tIMGUI_API void                  TableLoadSettings(ImGuiTable* table);\n\tIMGUI_API void                  TableSaveSettings(ImGuiTable* table);\n\tIMGUI_API void                  TableResetSettings(ImGuiTable* table);\n\tIMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table);\n\tIMGUI_API void                  TableSettingsAddSettingsHandler();\n\tIMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count);\n\tIMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);\n\n\t// Tab Bars\n\tinline    ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; }\n\tIMGUI_API bool          BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);\n\tIMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);\n\tIMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order);\n\tIMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar);\n\tinline int              TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); }\n\tIMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);\n\tIMGUI_API void          TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);\n\tIMGUI_API void          TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);\n\tIMGUI_API void          TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);\n\tIMGUI_API void          TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset);\n\tIMGUI_API void          TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos);\n\tIMGUI_API bool          TabBarProcessReorder(ImGuiTabBar* tab_bar);\n\tIMGUI_API bool          TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window);\n\tIMGUI_API ImVec2        TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker);\n\tIMGUI_API ImVec2        TabItemCalcSize(ImGuiWindow* window);\n\tIMGUI_API void          TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);\n\tIMGUI_API void          TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped);\n\n\t// Render helpers\n\t// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.\n\t// NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)\n\tIMGUI_API void          RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);\n\tIMGUI_API void          RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);\n\tIMGUI_API void          RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);\n\tIMGUI_API void          RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);\n\tIMGUI_API void          RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known);\n\tIMGUI_API void          RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);\n\tIMGUI_API void          RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);\n\tIMGUI_API void          RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0);\n\tIMGUI_API void          RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight\n\tIMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text.\n\tIMGUI_API void          RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow);\n\n\t// Render helpers (those functions don't access any ImGui state!)\n\tIMGUI_API void          RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f);\n\tIMGUI_API void          RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col);\n\tIMGUI_API void          RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);\n\tIMGUI_API void          RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);\n\tIMGUI_API void          RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);\n\tIMGUI_API void          RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding);\n\n\t// Widgets\n\tIMGUI_API void          TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);\n\tIMGUI_API bool          ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);\n\tIMGUI_API bool          ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0);\n\tIMGUI_API bool          ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0);\n\tIMGUI_API void          SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f);\n\tIMGUI_API void          SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width);\n\tIMGUI_API bool          CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value);\n\tIMGUI_API bool          CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value);\n\n\t// Widgets: Window Decorations\n\tIMGUI_API bool          CloseButton(ImGuiID id, const ImVec2& pos);\n\tIMGUI_API bool          CollapseButton(ImGuiID id, const ImVec2& pos);\n\tIMGUI_API void          Scrollbar(ImGuiAxis axis);\n\tIMGUI_API bool          ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags);\n\tIMGUI_API ImRect        GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis);\n\tIMGUI_API ImGuiID       GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);\n\tIMGUI_API ImGuiID       GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners\n\tIMGUI_API ImGuiID       GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir);\n\n\t// Widgets low-level behaviors\n\tIMGUI_API bool          ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);\n\tIMGUI_API bool          DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags);\n\tIMGUI_API bool          SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);\n\tIMGUI_API bool          SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0);\n\tIMGUI_API bool          TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);\n\tIMGUI_API void          TreePushOverrideID(ImGuiID id);\n\tIMGUI_API void          TreeNodeSetOpen(ImGuiID id, bool open);\n\tIMGUI_API bool          TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags);   // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.\n\n\t// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.\n\t// To use them externally (for custom widget) you may need an \"extern template\" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).\n\t// e.g. \" extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); \"\n\ttemplate<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);\n\ttemplate<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API T     ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);\n\ttemplate<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags);\n\ttemplate<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);\n\ttemplate<typename T>                                        IMGUI_API T     RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);\n\ttemplate<typename T>                                        IMGUI_API bool  CheckboxFlagsT(const char* label, T* flags, T flags_value);\n\n\t// Data type helpers\n\tIMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type);\n\tIMGUI_API int           DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);\n\tIMGUI_API void          DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2);\n\tIMGUI_API bool          DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format);\n\tIMGUI_API int           DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2);\n\tIMGUI_API bool          DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max);\n\n\t// InputText\n\tIMGUI_API bool          InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);\n\tIMGUI_API void          InputTextDeactivateHook(ImGuiID id);\n\tIMGUI_API bool          TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);\n\tIMGUI_API bool          TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);\n\tinline bool             TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }\n\tinline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active\n\n\t// Color\n\tIMGUI_API void          ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);\n\tIMGUI_API void          ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags);\n\tIMGUI_API void          ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags);\n\n\t// Plot\n\tIMGUI_API int           PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg);\n\n\t// Shade functions (write over already created vertices)\n\tIMGUI_API void          ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);\n\tIMGUI_API void          ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);\n\n\t// Garbage collection\n\tIMGUI_API void          GcCompactTransientMiscBuffers();\n\tIMGUI_API void          GcCompactTransientWindowBuffers(ImGuiWindow* window);\n\tIMGUI_API void          GcAwakeTransientWindowBuffers(ImGuiWindow* window);\n\n\t// Debug Log\n\tIMGUI_API void          DebugLog(const char* fmt, ...) IM_FMTARGS(1);\n\tIMGUI_API void          DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1);\n\n\t// Debug Tools\n\tIMGUI_API void          ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);\n\tIMGUI_API void          ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);\n\tIMGUI_API void          ErrorCheckUsingSetCursorPosToExtendParentBoundaries();\n\tIMGUI_API void          DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255));\n\tIMGUI_API void          DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255));\n\tIMGUI_API void          DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255));\n\tIMGUI_API void          DebugLocateItem(ImGuiID target_id);                     // Call sparingly: only 1 at the same time!\n\tIMGUI_API void          DebugLocateItemOnHover(ImGuiID target_id);              // Only call on reaction to a mouse Hover: because only 1 at the same time!\n\tIMGUI_API void          DebugLocateItemResolveWithLastItem();\n\tinline void             DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }\n\tIMGUI_API void          ShowFontAtlas(ImFontAtlas* atlas);\n\tIMGUI_API void          DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end);\n\tIMGUI_API void          DebugNodeColumns(ImGuiOldColumns* columns);\n\tIMGUI_API void          DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label);\n\tIMGUI_API void          DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);\n\tIMGUI_API void          DebugNodeFont(ImFont* font);\n\tIMGUI_API void          DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph);\n\tIMGUI_API void          DebugNodeStorage(ImGuiStorage* storage, const char* label);\n\tIMGUI_API void          DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label);\n\tIMGUI_API void          DebugNodeTable(ImGuiTable* table);\n\tIMGUI_API void          DebugNodeTableSettings(ImGuiTableSettings* settings);\n\tIMGUI_API void          DebugNodeInputTextState(ImGuiInputTextState* state);\n\tIMGUI_API void          DebugNodeWindow(ImGuiWindow* window, const char* label);\n\tIMGUI_API void          DebugNodeWindowSettings(ImGuiWindowSettings* settings);\n\tIMGUI_API void          DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label);\n\tIMGUI_API void          DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack);\n\tIMGUI_API void          DebugNodeViewport(ImGuiViewportP* viewport);\n\tIMGUI_API void          DebugRenderKeyboardPreview(ImDrawList* draw_list);\n\tIMGUI_API void          DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb);\n\n\t// Obsolete functions\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tinline void     SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); }      // Changed in 1.89\n\tinline bool     TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); }   // Renamed in 1.89\n\n\t// Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets that used FocusableItemRegister():\n\t//  (Old) IMGUI_VERSION_NUM  < 18209: using 'ItemAdd(....)'                              and 'bool tab_focused = FocusableItemRegister(...)'\n\t//  (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)'  and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0'\n\t//  (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)'     and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))' (WIP)\n\t// Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText()\n\tinline bool     FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd()\n\tinline void     FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); }                              // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem\n#endif\n#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO\n\tinline bool     IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity!\n#endif\n} // namespace ImGui\n\n//-----------------------------------------------------------------------------\n// [SECTION] ImFontAtlas internal API\n//-----------------------------------------------------------------------------\n\n// This structure is likely to evolve as we add support for incremental atlas updates\nstruct ImFontBuilderIO\n{\n\tbool    (*FontBuilder_Build)(ImFontAtlas* atlas);\n};\n\n// Helper for font builder\n#ifdef IMGUI_ENABLE_STB_TRUETYPE\nIMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype();\n#endif\nIMGUI_API void      ImFontAtlasBuildInit(ImFontAtlas* atlas);\nIMGUI_API void      ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);\nIMGUI_API void      ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);\nIMGUI_API void      ImFontAtlasBuildFinish(ImFontAtlas* atlas);\nIMGUI_API void      ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value);\nIMGUI_API void      ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value);\nIMGUI_API void      ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);\nIMGUI_API void      ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);\n\n//-----------------------------------------------------------------------------\n// [SECTION] Test Engine specific hooks (imgui_test_engine)\n//-----------------------------------------------------------------------------\n\n#ifdef IMGUI_ENABLE_TEST_ENGINE\nextern void         ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data);           // item_data may be NULL\nextern void         ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);\nextern void         ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...);\nextern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id);\n\n// In IMGUI_VERSION_NUM >= 18934: changed IMGUI_TEST_ENGINE_ITEM_ADD(bb,id) to IMGUI_TEST_ENGINE_ITEM_ADD(id,bb,item_data);\n#define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA)      if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _ID, _BB, _ITEM_DATA)    // Register item bounding box\n#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS)      if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS)    // Register item label and status flags (optional)\n#define IMGUI_TEST_ENGINE_LOG(_FMT,...)                     if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__)           // Custom log entry from user land into test log\n#else\n#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID)                 ((void)0)\n#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS)      ((void)g)\n#endif\n\n//-----------------------------------------------------------------------------\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#elif defined(__GNUC__)\n#pragma GCC diagnostic pop\n#endif\n\n#ifdef _MSC_VER\n#pragma warning (pop)\n#endif\n\n#endif // #ifndef IMGUI_DISABLE\n"
  },
  {
    "path": "KBotExt/imgui/imgui_tables.cpp",
    "content": "// dear imgui, v1.89.9\n// (tables and columns code)\n\n/*\n\nIndex of this file:\n\n// [SECTION] Commentary\n// [SECTION] Header mess\n// [SECTION] Tables: Main code\n// [SECTION] Tables: Simple accessors\n// [SECTION] Tables: Row changes\n// [SECTION] Tables: Columns changes\n// [SECTION] Tables: Columns width management\n// [SECTION] Tables: Drawing\n// [SECTION] Tables: Sorting\n// [SECTION] Tables: Headers\n// [SECTION] Tables: Context Menu\n// [SECTION] Tables: Settings (.ini data)\n// [SECTION] Tables: Garbage Collection\n// [SECTION] Tables: Debugging\n// [SECTION] Columns, BeginColumns, EndColumns, etc.\n\n*/\n\n// Navigating this file:\n// - In Visual Studio IDE: CTRL+comma (\"Edit.GoToAll\") can follow symbols in comments, whereas CTRL+F12 (\"Edit.GoToImplementation\") cannot.\n// - With Visual Assist installed: ALT+G (\"VAssistX.GoToImplementation\") can also follow symbols in comments.\n\n//-----------------------------------------------------------------------------\n// [SECTION] Commentary\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// Typical tables call flow: (root level is generally public API):\n//-----------------------------------------------------------------------------\n// - BeginTable()                               user begin into a table\n//    | BeginChild()                            - (if ScrollX/ScrollY is set)\n//    | TableBeginInitMemory()                  - first time table is used\n//    | TableResetSettings()                    - on settings reset\n//    | TableLoadSettings()                     - on settings load\n//    | TableBeginApplyRequests()               - apply queued resizing/reordering/hiding requests\n//    | - TableSetColumnWidth()                 - apply resizing width (for mouse resize, often requested by previous frame)\n//    |    - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width\n// - TableSetupColumn()                         user submit columns details (optional)\n// - TableSetupScrollFreeze()                   user submit scroll freeze information (optional)\n//-----------------------------------------------------------------------------\n// - TableUpdateLayout() [Internal]             followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow().\n//    | TableSetupDrawChannels()                - setup ImDrawList channels\n//    | TableUpdateBorders()                    - detect hovering columns for resize, ahead of contents submission\n//    | TableDrawContextMenu()                  - draw right-click context menu\n//-----------------------------------------------------------------------------\n// - TableHeadersRow() or TableHeader()         user submit a headers row (optional)\n//    | TableSortSpecsClickColumn()             - when left-clicked: alter sort order and sort direction\n//    | TableOpenContextMenu()                  - when right-clicked: trigger opening of the default context menu\n// - TableGetSortSpecs()                        user queries updated sort specs (optional, generally after submitting headers)\n// - TableNextRow()                             user begin into a new row (also automatically called by TableHeadersRow())\n//    | TableEndRow()                           - finish existing row\n//    | TableBeginRow()                         - add a new row\n// - TableSetColumnIndex() / TableNextColumn()  user begin into a cell\n//    | TableEndCell()                          - close existing column/cell\n//    | TableBeginCell()                        - enter into current column/cell\n// - [...]                                      user emit contents\n//-----------------------------------------------------------------------------\n// - EndTable()                                 user ends the table\n//    | TableDrawBorders()                      - draw outer borders, inner vertical borders\n//    | TableMergeDrawChannels()                - merge draw channels if clipping isn't required\n//    | EndChild()                              - (if ScrollX/ScrollY is set)\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// TABLE SIZING\n//-----------------------------------------------------------------------------\n// (Read carefully because this is subtle but it does make sense!)\n//-----------------------------------------------------------------------------\n// About 'outer_size':\n// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags.\n// Default value is ImVec2(0.0f, 0.0f).\n//   X\n//   - outer_size.x <= 0.0f  ->  Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge.\n//   - outer_size.x  > 0.0f  ->  Set Fixed width.\n//   Y with ScrollX/ScrollY disabled: we output table directly in current window\n//   - outer_size.y  < 0.0f  ->  Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll.\n//   - outer_size.y  = 0.0f  ->  No minimum height (but will auto extend, unless _NoHostExtendY is set)\n//   - outer_size.y  > 0.0f  ->  Set Minimum height (but will auto extend, unless _NoHostExtendY is set)\n//   Y with ScrollX/ScrollY enabled: using a child window for scrolling\n//   - outer_size.y  < 0.0f  ->  Bottom-align. Not meaningful if parent window can vertically scroll.\n//   - outer_size.y  = 0.0f  ->  Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window.\n//   - outer_size.y  > 0.0f  ->  Set Exact height. Recommended when using Scrolling on any axis.\n//-----------------------------------------------------------------------------\n// Outer size is also affected by the NoHostExtendX/NoHostExtendY flags.\n// Important to note how the two flags have slightly different behaviors!\n//   - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used.\n//   - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible.\n// In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height.\n// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not useful and not easily noticeable).\n//-----------------------------------------------------------------------------\n// About 'inner_width':\n//   With ScrollX disabled:\n//   - inner_width          ->  *ignored*\n//   With ScrollX enabled:\n//   - inner_width  < 0.0f  ->  *illegal* fit in known width (right align from outer_size.x) <-- weird\n//   - inner_width  = 0.0f  ->  fit in outer_width: Fixed size columns will take space they need (if avail, otherwise shrink down), Stretch columns becomes Fixed columns.\n//   - inner_width  > 0.0f  ->  override scrolling width, generally to be larger than outer_size.x. Fixed column take space they need (if avail, otherwise shrink down), Stretch columns share remaining space!\n//-----------------------------------------------------------------------------\n// Details:\n// - If you want to use Stretch columns with ScrollX, you generally need to specify 'inner_width' otherwise the concept\n//   of \"available space\" doesn't make sense.\n// - Even if not really useful, we allow 'inner_width < outer_size.x' for consistency and to facilitate understanding\n//   of what the value does.\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// COLUMNS SIZING POLICIES\n// (Reference: ImGuiTableFlags_SizingXXX flags and ImGuiTableColumnFlags_WidthXXX flags)\n//-----------------------------------------------------------------------------\n// About overriding column sizing policy and width/weight with TableSetupColumn():\n// We use a default parameter of -1 for 'init_width'/'init_weight'.\n//   - with ImGuiTableColumnFlags_WidthFixed,    init_width  <= 0 (default)  --> width is automatic\n//   - with ImGuiTableColumnFlags_WidthFixed,    init_width  >  0 (explicit) --> width is custom\n//   - with ImGuiTableColumnFlags_WidthStretch,  init_weight <= 0 (default)  --> weight is 1.0f\n//   - with ImGuiTableColumnFlags_WidthStretch,  init_weight >  0 (explicit) --> weight is custom\n// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f)\n// and you can fit a 100.0f wide item in it without clipping and with padding honored.\n//-----------------------------------------------------------------------------\n// About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag)\n//   - with Table policy ImGuiTableFlags_SizingFixedFit      --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width\n//   - with Table policy ImGuiTableFlags_SizingFixedSame     --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width\n//   - with Table policy ImGuiTableFlags_SizingStretchSame   --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f\n//   - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents\n// Default Width and default Weight can be overridden when calling TableSetupColumn().\n//-----------------------------------------------------------------------------\n// About mixing Fixed/Auto and Stretch columns together:\n//   - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.\n//   - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place!\n//     that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in.\n//   - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents.\n//   - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weights/widths.\n//-----------------------------------------------------------------------------\n// About using column width:\n// If a column is manually resizable or has a width specified with TableSetupColumn():\n//   - you may use GetContentRegionAvail().x to query the width available in a given column.\n//   - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width.\n// If the column is not resizable and has no width specified with TableSetupColumn():\n//   - its width will be automatic and be set to the max of items submitted.\n//   - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN).\n//   - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN).\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// TABLES CLIPPING/CULLING\n//-----------------------------------------------------------------------------\n// About clipping/culling of Rows in Tables:\n// - For large numbers of rows, it is recommended you use ImGuiListClipper to submit only visible rows.\n//   ImGuiListClipper is reliant on the fact that rows are of equal height.\n//   See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper.\n// - Note that auto-resizing columns don't play well with using the clipper.\n//   By default a table with _ScrollX but without _Resizable will have column auto-resize.\n//   So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns width explicitly with _WidthFixed.\n//-----------------------------------------------------------------------------\n// About clipping/culling of Columns in Tables:\n// - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing\n//   width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know\n//   it is not going to contribute to row height.\n//   In many situations, you may skip submitting contents for every column but one (e.g. the first one).\n// - Case A: column is not hidden by user, and at least partially in sight (most common case).\n// - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output.\n// - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.).\n//\n//                        [A]         [B]          [C]\n//  TableNextColumn():    true        false        false       -> [userland] when TableNextColumn() / TableSetColumnIndex() returns false, user can skip submitting items but only if the column doesn't contribute to row height.\n//          SkipItems:    false       false        true        -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output.\n//           ClipRect:    normal      zero-width   zero-width  -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way.\n//  ImDrawList output:    normal      dummy        dummy       -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway).\n//\n// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row.\n//   However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer.\n//-----------------------------------------------------------------------------\n// About clipping/culling of whole Tables:\n// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false.\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// [SECTION] Header mess\n//-----------------------------------------------------------------------------\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#ifndef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS\n#endif\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_internal.h\"\n\n// System includes\n#include <stdint.h>     // intptr_t\n\n// Visual Studio warnings\n#ifdef _MSC_VER\n#pragma warning (disable: 4127)     // condition expression is constant\n#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen\n#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later\n#pragma warning (disable: 5054)     // operator '|': deprecated between enumerations of different types\n#endif\n#pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).\n#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n#endif\n\n// Clang/GCC warnings with -Weverything\n#if defined(__clang__)\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wold-style-cast\"                 // warning: use of old-style cast                            // yes, they are more terse.\n#pragma clang diagnostic ignored \"-Wfloat-equal\"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.\n#pragma clang diagnostic ignored \"-Wformat-nonliteral\"              // warning: format string is not a string literal            // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.\n#pragma clang diagnostic ignored \"-Wsign-conversion\"                // warning: implicit conversion changes signedness\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.\n#pragma clang diagnostic ignored \"-Wenum-enum-conversion\"           // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')\n#pragma clang diagnostic ignored \"-Wdeprecated-enum-enum-conversion\"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated\n#pragma clang diagnostic ignored \"-Wimplicit-int-float-conversion\"  // warning: implicit conversion from 'xxx' to 'float' may lose precision\n#elif defined(__GNUC__)\n#pragma GCC diagnostic ignored \"-Wpragmas\"                          // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wformat-nonliteral\"                // warning: format not a string literal, format string not checked\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"                  // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#endif\n\n//-----------------------------------------------------------------------------\n// [SECTION] Tables: Main code\n//-----------------------------------------------------------------------------\n// - TableFixFlags() [Internal]\n// - TableFindByID() [Internal]\n// - BeginTable()\n// - BeginTableEx() [Internal]\n// - TableBeginInitMemory() [Internal]\n// - TableBeginApplyRequests() [Internal]\n// - TableSetupColumnFlags() [Internal]\n// - TableUpdateLayout() [Internal]\n// - TableUpdateBorders() [Internal]\n// - EndTable()\n// - TableSetupColumn()\n// - TableSetupScrollFreeze()\n//-----------------------------------------------------------------------------\n\n// Configuration\nstatic const int TABLE_DRAW_CHANNEL_BG0 = 0;\nstatic const int TABLE_DRAW_CHANNEL_BG2_FROZEN = 1;\nstatic const int TABLE_DRAW_CHANNEL_NOCLIP = 2;                     // When using ImGuiTableFlags_NoClip (this becomes the last visible channel)\nstatic const float TABLE_BORDER_SIZE = 1.0f;    // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering.\nstatic const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f;    // Extend outside inner borders.\nstatic const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f;   // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped.\n\n// Helper\ninline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window)\n{\n\t// Adjust flags: set default sizing policy\n\tif ((flags & ImGuiTableFlags_SizingMask_) == 0)\n\t\tflags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame;\n\n\t// Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame\n\tif ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)\n\t\tflags |= ImGuiTableFlags_NoKeepColumnsVisible;\n\n\t// Adjust flags: enforce borders when resizable\n\tif (flags & ImGuiTableFlags_Resizable)\n\t\tflags |= ImGuiTableFlags_BordersInnerV;\n\n\t// Adjust flags: disable NoHostExtendX/NoHostExtendY if we have any scrolling going on\n\tif (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY))\n\t\tflags &= ~(ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY);\n\n\t// Adjust flags: NoBordersInBodyUntilResize takes priority over NoBordersInBody\n\tif (flags & ImGuiTableFlags_NoBordersInBodyUntilResize)\n\t\tflags &= ~ImGuiTableFlags_NoBordersInBody;\n\n\t// Adjust flags: disable saved settings if there's nothing to save\n\tif ((flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable)) == 0)\n\t\tflags |= ImGuiTableFlags_NoSavedSettings;\n\n\t// Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set)\n\tif (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings)\n\t\tflags |= ImGuiTableFlags_NoSavedSettings;\n\n\treturn flags;\n}\n\nImGuiTable* ImGui::TableFindByID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.Tables.GetByKey(id);\n}\n\n// Read about \"TABLE SIZING\" at the top of this file.\nbool    ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width)\n{\n\tImGuiID id = GetID(str_id);\n\treturn BeginTableEx(str_id, id, columns_count, flags, outer_size, inner_width);\n}\n\nbool    ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* outer_window = GetCurrentWindow();\n\tif (outer_window->SkipItems) // Consistent with other tables + beneficial side effect that assert on miscalling EndTable() will be more visible.\n\t\treturn false;\n\n\t// Sanity checks\n\tIM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS);\n\tif (flags & ImGuiTableFlags_ScrollX)\n\t\tIM_ASSERT(inner_width >= 0.0f);\n\n\t// If an outer size is specified ahead we will be able to early out when not visible. Exact clipping criteria may evolve.\n\tconst bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0;\n\tconst ImVec2 avail_size = GetContentRegionAvail();\n\tImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);\n\tImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);\n\tif (use_child_window && IsClippedEx(outer_rect, 0))\n\t{\n\t\tItemSize(outer_rect);\n\t\treturn false;\n\t}\n\n\t// Acquire storage for the table\n\tImGuiTable* table = g.Tables.GetOrAddByKey(id);\n\tconst ImGuiTableFlags table_last_flags = table->Flags;\n\n\t// Acquire temporary buffers\n\tconst int table_idx = g.Tables.GetIndex(table);\n\tif (++g.TablesTempDataStacked > g.TablesTempData.Size)\n\t\tg.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData());\n\tImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1];\n\ttemp_data->TableIndex = table_idx;\n\ttable->DrawSplitter = &table->TempData->DrawSplitter;\n\ttable->DrawSplitter->Clear();\n\n\t// Fix flags\n\ttable->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0;\n\tflags = TableFixFlags(flags, outer_window);\n\n\t// Initialize\n\tconst int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;\n\ttable->ID = id;\n\ttable->Flags = flags;\n\ttable->LastFrameActive = g.FrameCount;\n\ttable->OuterWindow = table->InnerWindow = outer_window;\n\ttable->ColumnsCount = columns_count;\n\ttable->IsLayoutLocked = false;\n\ttable->InnerWidth = inner_width;\n\ttemp_data->UserOuterSize = outer_size;\n\n\t// Instance data (for instance 0, TableID == TableInstanceID)\n\tImGuiID instance_id;\n\ttable->InstanceCurrent = (ImS16)instance_no;\n\tif (instance_no > 0)\n\t{\n\t\tIM_ASSERT(table->ColumnsCount == columns_count && \"BeginTable(): Cannot change columns count mid-frame while preserving same ID\");\n\t\tif (table->InstanceDataExtra.Size < instance_no)\n\t\t\ttable->InstanceDataExtra.push_back(ImGuiTableInstanceData());\n\t\tinstance_id = GetIDWithSeed(instance_no, GetIDWithSeed(\"##Instances\", NULL, id)); // Push \"##Instances\" followed by (int)instance_no in ID stack.\n\t}\n\telse\n\t{\n\t\tinstance_id = id;\n\t}\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\ttable_instance->TableInstanceID = instance_id;\n\n\t// When not using a child window, WorkRect.Max will grow as we append contents.\n\tif (use_child_window)\n\t{\n\t\t// Ensure no vertical scrollbar appears if we only want horizontal one, to make flag consistent\n\t\t// (we have no other way to disable vertical scrollbar of a window while keeping the horizontal one showing)\n\t\tImVec2 override_content_size(FLT_MAX, FLT_MAX);\n\t\tif ((flags & ImGuiTableFlags_ScrollX) && !(flags & ImGuiTableFlags_ScrollY))\n\t\t\toverride_content_size.y = FLT_MIN;\n\n\t\t// Ensure specified width (when not specified, Stretched columns will act as if the width == OuterWidth and\n\t\t// never lead to any scrolling). We don't handle inner_width < 0.0f, we could potentially use it to right-align\n\t\t// based on the right side of the child window work rect, which would require knowing ahead if we are going to\n\t\t// have decoration taking horizontal spaces (typically a vertical scrollbar).\n\t\tif ((flags & ImGuiTableFlags_ScrollX) && inner_width > 0.0f)\n\t\t\toverride_content_size.x = inner_width;\n\n\t\tif (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX)\n\t\t\tSetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f));\n\n\t\t// Reset scroll if we are reactivating it\n\t\tif ((table_last_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0)\n\t\t\tSetNextWindowScroll(ImVec2(0.0f, 0.0f));\n\n\t\t// Create scrolling region (without border and zero window padding)\n\t\tImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;\n\t\tBeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags);\n\t\ttable->InnerWindow = g.CurrentWindow;\n\t\ttable->WorkRect = table->InnerWindow->WorkRect;\n\t\ttable->OuterRect = table->InnerWindow->Rect();\n\t\ttable->InnerRect = table->InnerWindow->InnerRect;\n\t\tIM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f);\n\n\t\t// When using multiple instances, ensure they have the same amount of horizontal decorations (aka vertical scrollbar) so stretched columns can be aligned)\n\t\tif (instance_no == 0)\n\t\t{\n\t\t\ttable->HasScrollbarYPrev = table->HasScrollbarYCurr;\n\t\t\ttable->HasScrollbarYCurr = false;\n\t\t}\n\t\ttable->HasScrollbarYCurr |= table->InnerWindow->ScrollbarY;\n\t}\n\telse\n\t{\n\t\t// For non-scrolling tables, WorkRect == OuterRect == InnerRect.\n\t\t// But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable().\n\t\ttable->WorkRect = table->OuterRect = table->InnerRect = outer_rect;\n\t}\n\n\t// Push a standardized ID for both child-using and not-child-using tables\n\tPushOverrideID(id);\n\tif (instance_no > 0)\n\t\tPushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol.\n\n\t// Backup a copy of host window members we will modify\n\tImGuiWindow* inner_window = table->InnerWindow;\n\ttable->HostIndentX = inner_window->DC.Indent.x;\n\ttable->HostClipRect = inner_window->ClipRect;\n\ttable->HostSkipItems = inner_window->SkipItems;\n\ttemp_data->HostBackupWorkRect = inner_window->WorkRect;\n\ttemp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect;\n\ttemp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset;\n\ttemp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize;\n\ttemp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize;\n\ttemp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos;\n\ttemp_data->HostBackupItemWidth = outer_window->DC.ItemWidth;\n\ttemp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;\n\tinner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);\n\n\t// Padding and Spacing\n\t// - None               ........Content..... Pad .....Content........\n\t// - PadOuter           | Pad ..Content..... Pad .....Content.. Pad |\n\t// - PadInner           ........Content.. Pad | Pad ..Content........\n\t// - PadOuter+PadInner  | Pad ..Content.. Pad | Pad ..Content.. Pad |\n\tconst bool pad_outer_x = (flags & ImGuiTableFlags_NoPadOuterX) ? false : (flags & ImGuiTableFlags_PadOuterX) ? true : (flags & ImGuiTableFlags_BordersOuterV) != 0;\n\tconst bool pad_inner_x = (flags & ImGuiTableFlags_NoPadInnerX) ? false : true;\n\tconst float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f;\n\tconst float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f;\n\tconst float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f;\n\ttable->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border;\n\ttable->CellSpacingX2 = inner_spacing_explicit;\n\ttable->CellPaddingX = inner_padding_explicit;\n\n\tconst float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;\n\tconst float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f;\n\ttable->OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table->CellPaddingX;\n\n\ttable->CurrentColumn = -1;\n\ttable->CurrentRow = -1;\n\ttable->RowBgColorCounter = 0;\n\ttable->LastRowFlags = ImGuiTableRowFlags_None;\n\ttable->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect;\n\ttable->InnerClipRect.ClipWith(table->WorkRect);     // We need this to honor inner_width\n\ttable->InnerClipRect.ClipWithFull(table->HostClipRect);\n\ttable->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;\n\n\ttable->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow\n\ttable->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()\n\ttable->RowCellPaddingY = 0.0f;\n\ttable->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any\n\ttable->FreezeColumnsRequest = table->FreezeColumnsCount = 0;\n\ttable->IsUnfrozenRows = true;\n\ttable->DeclColumnsCount = 0;\n\n\t// Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders()\n\ttable->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong);\n\ttable->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight);\n\n\t// Make table current\n\tg.CurrentTable = table;\n\touter_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX();\n\touter_window->DC.CurrentTableIdx = table_idx;\n\tif (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly.\n\t\tinner_window->DC.CurrentTableIdx = table_idx;\n\n\tif ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0)\n\t\ttable->IsResetDisplayOrderRequest = true;\n\n\t// Mark as used to avoid GC\n\tif (table_idx >= g.TablesLastTimeActive.Size)\n\t\tg.TablesLastTimeActive.resize(table_idx + 1, -1.0f);\n\tg.TablesLastTimeActive[table_idx] = (float)g.Time;\n\ttemp_data->LastTimeActive = (float)g.Time;\n\ttable->MemoryCompacted = false;\n\n\t// Setup memory buffer (clear data if columns count changed)\n\tImGuiTableColumn* old_columns_to_preserve = NULL;\n\tvoid* old_columns_raw_data = NULL;\n\tconst int old_columns_count = table->Columns.size();\n\tif (old_columns_count != 0 && old_columns_count != columns_count)\n\t{\n\t\t// Attempt to preserve width on column count change (#4046)\n\t\told_columns_to_preserve = table->Columns.Data;\n\t\told_columns_raw_data = table->RawData;\n\t\ttable->RawData = NULL;\n\t}\n\tif (table->RawData == NULL)\n\t{\n\t\tTableBeginInitMemory(table, columns_count);\n\t\ttable->IsInitializing = table->IsSettingsRequestLoad = true;\n\t}\n\tif (table->IsResetAllRequest)\n\t\tTableResetSettings(table);\n\tif (table->IsInitializing)\n\t{\n\t\t// Initialize\n\t\ttable->SettingsOffset = -1;\n\t\ttable->IsSortSpecsDirty = true;\n\t\ttable->InstanceInteracted = -1;\n\t\ttable->ContextPopupColumn = -1;\n\t\ttable->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;\n\t\ttable->AutoFitSingleColumn = -1;\n\t\ttable->HoveredColumnBody = table->HoveredColumnBorder = -1;\n\t\tfor (int n = 0; n < columns_count; n++)\n\t\t{\n\t\t\tImGuiTableColumn* column = &table->Columns[n];\n\t\t\tif (old_columns_to_preserve && n < old_columns_count)\n\t\t\t{\n\t\t\t\t// FIXME: We don't attempt to preserve column order in this path.\n\t\t\t\t*column = old_columns_to_preserve[n];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfloat width_auto = column->WidthAuto;\n\t\t\t\t*column = ImGuiTableColumn();\n\t\t\t\tcolumn->WidthAuto = width_auto;\n\t\t\t\tcolumn->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker\n\t\t\t\tcolumn->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true;\n\t\t\t}\n\t\t\tcolumn->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;\n\t\t}\n\t}\n\tif (old_columns_raw_data)\n\t\tIM_FREE(old_columns_raw_data);\n\n\t// Load settings\n\tif (table->IsSettingsRequestLoad)\n\t\tTableLoadSettings(table);\n\n\t// Handle DPI/font resize\n\t// This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well.\n\t// It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition.\n\t// FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory.\n\t// This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path.\n\tconst float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ?\n\tif (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit)\n\t{\n\t\tconst float scale_factor = new_ref_scale_unit / table->RefScale;\n\t\t//IMGUI_DEBUG_PRINT(\"[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\\n\", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor);\n\t\tfor (int n = 0; n < columns_count; n++)\n\t\t\ttable->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor;\n\t}\n\ttable->RefScale = new_ref_scale_unit;\n\n\t// Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call..\n\t// This is not strictly necessary but will reduce cases were \"out of table\" output will be misleading to the user.\n\t// Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option.\n\tinner_window->SkipItems = true;\n\n\t// Clear names\n\t// At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn()\n\tif (table->ColumnsNames.Buf.Size > 0)\n\t\ttable->ColumnsNames.Buf.resize(0);\n\n\t// Apply queued resizing/reordering/hiding requests\n\tTableBeginApplyRequests(table);\n\n\treturn true;\n}\n\n// For reference, the average total _allocation count_ for a table is:\n// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables[])\n// + 1 (for table->RawData allocated below)\n// + 1 (for table->ColumnsNames, if names are used)\n// Shared allocations for the maximum number of simultaneously nested tables (generally a very small number)\n// + 1 (for table->Splitter._Channels)\n// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels)\n// Where active_channels_count is variable but often == columns_count or == columns_count + 1, see TableSetupDrawChannels() for details.\n// Unused channels don't perform their +2 allocations.\nvoid ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)\n{\n\t// Allocate single buffer for our arrays\n\tconst int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count);\n\tImSpanAllocator<6> span_allocator;\n\tspan_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn));\n\tspan_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx));\n\tspan_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4);\n\tfor (int n = 3; n < 6; n++)\n\t\tspan_allocator.Reserve(n, columns_bit_array_size);\n\ttable->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());\n\tmemset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());\n\tspan_allocator.SetArenaBasePtr(table->RawData);\n\tspan_allocator.GetSpan(0, &table->Columns);\n\tspan_allocator.GetSpan(1, &table->DisplayOrderToIndex);\n\tspan_allocator.GetSpan(2, &table->RowCellData);\n\ttable->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3);\n\ttable->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4);\n\ttable->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5);\n}\n\n// Apply queued resizing/reordering/hiding requests\nvoid ImGui::TableBeginApplyRequests(ImGuiTable* table)\n{\n\t// Handle resizing request\n\t// (We process this in the TableBegin() of the first instance of each table)\n\t// FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling?\n\tif (table->InstanceCurrent == 0)\n\t{\n\t\tif (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX)\n\t\t\tTableSetColumnWidth(table->ResizedColumn, table->ResizedColumnNextWidth);\n\t\ttable->LastResizedColumn = table->ResizedColumn;\n\t\ttable->ResizedColumnNextWidth = FLT_MAX;\n\t\ttable->ResizedColumn = -1;\n\n\t\t// Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy.\n\t\t// FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings.\n\t\tif (table->AutoFitSingleColumn != -1)\n\t\t{\n\t\t\tTableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto);\n\t\t\ttable->AutoFitSingleColumn = -1;\n\t\t}\n\t}\n\n\t// Handle reordering request\n\t// Note: we don't clear ReorderColumn after handling the request.\n\tif (table->InstanceCurrent == 0)\n\t{\n\t\tif (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1)\n\t\t\ttable->ReorderColumn = -1;\n\t\ttable->HeldHeaderColumn = -1;\n\t\tif (table->ReorderColumn != -1 && table->ReorderColumnDir != 0)\n\t\t{\n\t\t\t// We need to handle reordering across hidden columns.\n\t\t\t// In the configuration below, moving C to the right of E will lead to:\n\t\t\t//    ... C [D] E  --->  ... [D] E  C   (Column name/index)\n\t\t\t//    ... 2  3  4        ...  2  3  4   (Display order)\n\t\t\tconst int reorder_dir = table->ReorderColumnDir;\n\t\t\tIM_ASSERT(reorder_dir == -1 || reorder_dir == +1);\n\t\t\tIM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable);\n\t\t\tImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn];\n\t\t\tImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn];\n\t\t\tIM_UNUSED(dst_column);\n\t\t\tconst int src_order = src_column->DisplayOrder;\n\t\t\tconst int dst_order = dst_column->DisplayOrder;\n\t\t\tsrc_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order;\n\t\t\tfor (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir)\n\t\t\t\ttable->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir;\n\t\t\tIM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir);\n\n\t\t\t// Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former.\n\t\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\t\ttable->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n;\n\t\t\ttable->ReorderColumnDir = 0;\n\t\t\ttable->IsSettingsDirty = true;\n\t\t}\n\t}\n\n\t// Handle display order reset request\n\tif (table->IsResetDisplayOrderRequest)\n\t{\n\t\tfor (int n = 0; n < table->ColumnsCount; n++)\n\t\t\ttable->DisplayOrderToIndex[n] = table->Columns[n].DisplayOrder = (ImGuiTableColumnIdx)n;\n\t\ttable->IsResetDisplayOrderRequest = false;\n\t\ttable->IsSettingsDirty = true;\n\t}\n}\n\n// Adjust flags: default width mode + stretch columns are not allowed when auto extending\nstatic void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in)\n{\n\tImGuiTableColumnFlags flags = flags_in;\n\n\t// Sizing Policy\n\tif ((flags & ImGuiTableColumnFlags_WidthMask_) == 0)\n\t{\n\t\tconst ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);\n\t\tif (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame)\n\t\t\tflags |= ImGuiTableColumnFlags_WidthFixed;\n\t\telse\n\t\t\tflags |= ImGuiTableColumnFlags_WidthStretch;\n\t}\n\telse\n\t{\n\t\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used.\n\t}\n\n\t// Resize\n\tif ((table->Flags & ImGuiTableFlags_Resizable) == 0)\n\t\tflags |= ImGuiTableColumnFlags_NoResize;\n\n\t// Sorting\n\tif ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending))\n\t\tflags |= ImGuiTableColumnFlags_NoSort;\n\n\t// Indentation\n\tif ((flags & ImGuiTableColumnFlags_IndentMask_) == 0)\n\t\tflags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable;\n\n\t// Alignment\n\t//if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0)\n\t//    flags |= ImGuiTableColumnFlags_AlignCenter;\n\t//IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used.\n\n\t// Preserve status flags\n\tcolumn->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_);\n\n\t// Build an ordered list of available sort directions\n\tcolumn->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0;\n\tif (table->Flags & ImGuiTableFlags_Sortable)\n\t{\n\t\tint count = 0, mask = 0, list = 0;\n\t\tif ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending;  list |= ImGuiSortDirection_Ascending << (count << 1); count++; }\n\t\tif ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }\n\t\tif ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending;  list |= ImGuiSortDirection_Ascending << (count << 1); count++; }\n\t\tif ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }\n\t\tif ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; }\n\t\tcolumn->SortDirectionsAvailList = (ImU8)list;\n\t\tcolumn->SortDirectionsAvailMask = (ImU8)mask;\n\t\tcolumn->SortDirectionsAvailCount = (ImU8)count;\n\t\tImGui::TableFixColumnSortDirection(table, column);\n\t}\n}\n\n// Layout columns for the frame. This is in essence the followup to BeginTable() and this is our largest function.\n// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() and other TableSetupXXXXX() functions to be called first.\n// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns.\n// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns?\nvoid ImGui::TableUpdateLayout(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(table->IsLayoutLocked == false);\n\n\tconst ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);\n\ttable->IsDefaultDisplayOrder = true;\n\ttable->ColumnsEnabledCount = 0;\n\tImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount);\n\tImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount);\n\ttable->LeftMostEnabledColumn = -1;\n\ttable->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE\n\n\t// [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns.\n\t// Process columns in their visible orders as we are building the Prev/Next indices.\n\tint count_fixed = 0;                // Number of columns that have fixed sizing policies\n\tint count_stretch = 0;              // Number of columns that have stretch sizing policies\n\tint prev_visible_column_idx = -1;\n\tbool has_auto_fit_request = false;\n\tbool has_resizable = false;\n\tfloat stretch_sum_width_auto = 0.0f;\n\tfloat fixed_max_width_auto = 0.0f;\n\tfor (int order_n = 0; order_n < table->ColumnsCount; order_n++)\n\t{\n\t\tconst int column_n = table->DisplayOrderToIndex[order_n];\n\t\tif (column_n != order_n)\n\t\t\ttable->IsDefaultDisplayOrder = false;\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t\t// Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame.\n\t\t// It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway.\n\t\t// We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect.\n\t\tif (table->DeclColumnsCount <= column_n)\n\t\t{\n\t\t\tTableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None);\n\t\t\tcolumn->NameOffset = -1;\n\t\t\tcolumn->UserID = 0;\n\t\t\tcolumn->InitStretchWeightOrWidth = -1.0f;\n\t\t}\n\n\t\t// Update Enabled state, mark settings and sort specs dirty\n\t\tif (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))\n\t\t\tcolumn->IsUserEnabledNextFrame = true;\n\t\tif (column->IsUserEnabled != column->IsUserEnabledNextFrame)\n\t\t{\n\t\t\tcolumn->IsUserEnabled = column->IsUserEnabledNextFrame;\n\t\t\ttable->IsSettingsDirty = true;\n\t\t}\n\t\tcolumn->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0;\n\n\t\tif (column->SortOrder != -1 && !column->IsEnabled)\n\t\t\ttable->IsSortSpecsDirty = true;\n\t\tif (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))\n\t\t\ttable->IsSortSpecsDirty = true;\n\n\t\t// Auto-fit unsized columns\n\t\tconst bool start_auto_fit = (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f);\n\t\tif (start_auto_fit)\n\t\t\tcolumn->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames\n\n\t\tif (!column->IsEnabled)\n\t\t{\n\t\t\tcolumn->IndexWithinEnabledSet = -1;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mark as enabled and link to previous/next enabled column\n\t\tcolumn->PrevEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx;\n\t\tcolumn->NextEnabledColumn = -1;\n\t\tif (prev_visible_column_idx != -1)\n\t\t\ttable->Columns[prev_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n;\n\t\telse\n\t\t\ttable->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;\n\t\tcolumn->IndexWithinEnabledSet = table->ColumnsEnabledCount++;\n\t\tImBitArraySetBit(table->EnabledMaskByIndex, column_n);\n\t\tImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder);\n\t\tprev_visible_column_idx = column_n;\n\t\tIM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);\n\n\t\t// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)\n\t\t// Combine width from regular rows + width from headers unless requested not to.\n\t\tif (!column->IsPreserveWidthAuto)\n\t\t\tcolumn->WidthAuto = TableGetColumnWidthAuto(table, column);\n\n\t\t// Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)\n\t\tconst bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;\n\t\tif (column_is_resizable)\n\t\t\thas_resizable = true;\n\t\tif ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable)\n\t\t\tcolumn->WidthAuto = column->InitStretchWeightOrWidth;\n\n\t\tif (column->AutoFitQueue != 0x00)\n\t\t\thas_auto_fit_request = true;\n\t\tif (column->Flags & ImGuiTableColumnFlags_WidthStretch)\n\t\t{\n\t\t\tstretch_sum_width_auto += column->WidthAuto;\n\t\t\tcount_stretch++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto);\n\t\t\tcount_fixed++;\n\t\t}\n\t}\n\tif ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))\n\t\ttable->IsSortSpecsDirty = true;\n\ttable->RightMostEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx;\n\tIM_ASSERT(table->LeftMostEnabledColumn >= 0 && table->RightMostEnabledColumn >= 0);\n\n\t// [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible\n\t// to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing).\n\t// FIXME-TABLE: for always auto-resizing columns may not want to do that all the time.\n\tif (has_auto_fit_request && table->OuterWindow != table->InnerWindow)\n\t\ttable->InnerWindow->SkipItems = false;\n\tif (has_auto_fit_request)\n\t\ttable->IsSettingsDirty = true;\n\n\t// [Part 3] Fix column flags and record a few extra information.\n\tfloat sum_width_requests = 0.0f;    // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding.\n\tfloat stretch_sum_weights = 0.0f;   // Sum of all weights for stretch columns.\n\ttable->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))\n\t\t\tcontinue;\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t\tconst bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;\n\t\tif (column->Flags & ImGuiTableColumnFlags_WidthFixed)\n\t\t{\n\t\t\t// Apply same widths policy\n\t\t\tfloat width_auto = column->WidthAuto;\n\t\t\tif (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable))\n\t\t\t\twidth_auto = fixed_max_width_auto;\n\n\t\t\t// Apply automatic width\n\t\t\t// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)\n\t\t\tif (column->AutoFitQueue != 0x00)\n\t\t\t\tcolumn->WidthRequest = width_auto;\n\t\t\telse if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput)\n\t\t\t\tcolumn->WidthRequest = width_auto;\n\n\t\t\t// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets\n\t\t\t// (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very\n\t\t\t// large height (= first frame scrollbar display very off + clipper would skip lots of items).\n\t\t\t// This is merely making the side-effect less extreme, but doesn't properly fixes it.\n\t\t\t// FIXME: Move this to ->WidthGiven to avoid temporary lossyless?\n\t\t\t// FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller.\n\t\t\tif (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto)\n\t\t\t\tcolumn->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale?\n\t\t\tsum_width_requests += column->WidthRequest;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Initialize stretch weight\n\t\t\tif (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable)\n\t\t\t{\n\t\t\t\tif (column->InitStretchWeightOrWidth > 0.0f)\n\t\t\t\t\tcolumn->StretchWeight = column->InitStretchWeightOrWidth;\n\t\t\t\telse if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp)\n\t\t\t\t\tcolumn->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch;\n\t\t\t\telse\n\t\t\t\t\tcolumn->StretchWeight = 1.0f;\n\t\t\t}\n\n\t\t\tstretch_sum_weights += column->StretchWeight;\n\t\t\tif (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder)\n\t\t\t\ttable->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n;\n\t\t\tif (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder)\n\t\t\t\ttable->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n;\n\t\t}\n\t\tcolumn->IsPreserveWidthAuto = false;\n\t\tsum_width_requests += table->CellPaddingX * 2.0f;\n\t}\n\ttable->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;\n\ttable->ColumnsStretchSumWeights = stretch_sum_weights;\n\n\t// [Part 4] Apply final widths based on requested widths\n\tconst ImRect work_rect = table->WorkRect;\n\tconst float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);\n\tconst float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920)\n\tconst float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed);\n\tconst float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;\n\tfloat width_remaining_for_stretched_columns = width_avail_for_stretched_columns;\n\ttable->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))\n\t\t\tcontinue;\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t\t// Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest)\n\t\tif (column->Flags & ImGuiTableColumnFlags_WidthStretch)\n\t\t{\n\t\t\tfloat weight_ratio = column->StretchWeight / stretch_sum_weights;\n\t\t\tcolumn->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f);\n\t\t\twidth_remaining_for_stretched_columns -= column->WidthRequest;\n\t\t}\n\n\t\t// [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column\n\t\t// See additional comments in TableSetColumnWidth().\n\t\tif (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1)\n\t\t\tcolumn->Flags |= ImGuiTableColumnFlags_NoDirectResize_;\n\n\t\t// Assign final width, record width in case we will need to shrink\n\t\tcolumn->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth));\n\t\ttable->ColumnsGivenWidth += column->WidthGiven;\n\t}\n\n\t// [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column).\n\t// Using right-to-left distribution (more likely to match resizing cursor).\n\tif (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))\n\t\tfor (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)\n\t\t{\n\t\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))\n\t\t\t\tcontinue;\n\t\t\tImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];\n\t\t\tif (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))\n\t\t\t\tcontinue;\n\t\t\tcolumn->WidthRequest += 1.0f;\n\t\t\tcolumn->WidthGiven += 1.0f;\n\t\t\twidth_remaining_for_stretched_columns -= 1.0f;\n\t\t}\n\n\t// Determine if table is hovered which will be used to flag columns as hovered.\n\t// - In principle we'd like to use the equivalent of IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),\n\t//   but because our item is partially submitted at this point we use ItemHoverable() and a workaround (temporarily\n\t//   clear ActiveId, which is equivalent to the change provided by _AllowWhenBLockedByActiveItem).\n\t// - This allows columns to be marked as hovered when e.g. clicking a button inside the column, or using drag and drop.\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\ttable_instance->HoveredRowLast = table_instance->HoveredRowNext;\n\ttable_instance->HoveredRowNext = -1;\n\ttable->HoveredColumnBody = -1;\n\ttable->HoveredColumnBorder = -1;\n\tconst ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight));\n\tconst ImGuiID backup_active_id = g.ActiveId;\n\tg.ActiveId = 0;\n\tconst bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags_None);\n\tg.ActiveId = backup_active_id;\n\n\t// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column\n\t// Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping.\n\tint visible_n = 0;\n\tbool offset_x_frozen = (table->FreezeColumnsCount > 0);\n\tfloat offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;\n\tImRect host_clip_rect = table->InnerClipRect;\n\t//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;\n\tImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount);\n\tfor (int order_n = 0; order_n < table->ColumnsCount; order_n++)\n\t{\n\t\tconst int column_n = table->DisplayOrderToIndex[order_n];\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t\tcolumn->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen\n\n\t\tif (offset_x_frozen && table->FreezeColumnsCount == visible_n)\n\t\t{\n\t\t\toffset_x += work_rect.Min.x - table->OuterRect.Min.x;\n\t\t\toffset_x_frozen = false;\n\t\t}\n\n\t\t// Clear status flags\n\t\tcolumn->Flags &= ~ImGuiTableColumnFlags_StatusMask_;\n\n\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))\n\t\t{\n\t\t\t// Hidden column: clear a few fields and we are done with it for the remainder of the function.\n\t\t\t// We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper.\n\t\t\tcolumn->MinX = column->MaxX = column->WorkMinX = column->ClipRect.Min.x = column->ClipRect.Max.x = offset_x;\n\t\t\tcolumn->WidthGiven = 0.0f;\n\t\t\tcolumn->ClipRect.Min.y = work_rect.Min.y;\n\t\t\tcolumn->ClipRect.Max.y = FLT_MAX;\n\t\t\tcolumn->ClipRect.ClipWithFull(host_clip_rect);\n\t\t\tcolumn->IsVisibleX = column->IsVisibleY = column->IsRequestOutput = false;\n\t\t\tcolumn->IsSkipItems = true;\n\t\t\tcolumn->ItemWidth = 1.0f;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Detect hovered column\n\t\tif (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x)\n\t\t\ttable->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;\n\n\t\t// Lock start position\n\t\tcolumn->MinX = offset_x;\n\n\t\t// Lock width based on start position and minimum/maximum width for this position\n\t\tfloat max_width = TableGetMaxColumnWidth(table, column_n);\n\t\tcolumn->WidthGiven = ImMin(column->WidthGiven, max_width);\n\t\tcolumn->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth));\n\t\tcolumn->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;\n\n\t\t// Lock other positions\n\t\t// - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging.\n\t\t// - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column.\n\t\t// - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow.\n\t\t// - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter.\n\t\tcolumn->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1;\n\t\tcolumn->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max\n\t\tcolumn->ItemWidth = ImFloor(column->WidthGiven * 0.65f);\n\t\tcolumn->ClipRect.Min.x = column->MinX;\n\t\tcolumn->ClipRect.Min.y = work_rect.Min.y;\n\t\tcolumn->ClipRect.Max.x = column->MaxX; //column->WorkMaxX;\n\t\tcolumn->ClipRect.Max.y = FLT_MAX;\n\t\tcolumn->ClipRect.ClipWithFull(host_clip_rect);\n\n\t\t// Mark column as Clipped (not in sight)\n\t\t// Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables.\n\t\t// FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY.\n\t\t// Taking advantage of LastOuterHeight would yield good results there...\n\t\t// FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x,\n\t\t// and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else).\n\t\t// Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small.\n\t\tcolumn->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x);\n\t\tcolumn->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y);\n\t\tconst bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;\n\t\tif (is_visible)\n\t\t\tImBitArraySetBit(table->VisibleMaskByIndex, column_n);\n\n\t\t// Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output.\n\t\tcolumn->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;\n\n\t\t// Mark column as SkipItems (ignoring all items/layout)\n\t\tcolumn->IsSkipItems = !column->IsEnabled || table->HostSkipItems;\n\t\tif (column->IsSkipItems)\n\t\t\tIM_ASSERT(!is_visible);\n\n\t\t// Update status flags\n\t\tcolumn->Flags |= ImGuiTableColumnFlags_IsEnabled;\n\t\tif (is_visible)\n\t\t\tcolumn->Flags |= ImGuiTableColumnFlags_IsVisible;\n\t\tif (column->SortOrder != -1)\n\t\t\tcolumn->Flags |= ImGuiTableColumnFlags_IsSorted;\n\t\tif (table->HoveredColumnBody == column_n)\n\t\t\tcolumn->Flags |= ImGuiTableColumnFlags_IsHovered;\n\n\t\t// Alignment\n\t\t// FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in\n\t\t// many cases (to be able to honor this we might be able to store a log of cells width, per row, for\n\t\t// visible rows, but nav/programmatic scroll would have visible artifacts.)\n\t\t//if (column->Flags & ImGuiTableColumnFlags_AlignRight)\n\t\t//    column->WorkMinX = ImMax(column->WorkMinX, column->MaxX - column->ContentWidthRowsUnfrozen);\n\t\t//else if (column->Flags & ImGuiTableColumnFlags_AlignCenter)\n\t\t//    column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f);\n\n\t\t// Reset content width variables\n\t\tcolumn->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX;\n\t\tcolumn->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX;\n\n\t\t// Don't decrement auto-fit counters until container window got a chance to submit its items\n\t\tif (table->HostSkipItems == false)\n\t\t{\n\t\t\tcolumn->AutoFitQueue >>= 1;\n\t\t\tcolumn->CannotSkipItemsQueue >>= 1;\n\t\t}\n\n\t\tif (visible_n < table->FreezeColumnsCount)\n\t\t\thost_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x);\n\n\t\toffset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;\n\t\tvisible_n++;\n\t}\n\n\t// [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it)\n\t// Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either\n\t// because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu.\n\tconst float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x);\n\tif (is_hovering_table && table->HoveredColumnBody == -1)\n\t{\n\t\tif (g.IO.MousePos.x >= unused_x1)\n\t\t\ttable->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;\n\t}\n\tif (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable))\n\t\ttable->Flags &= ~ImGuiTableFlags_Resizable;\n\n\t// [Part 8] Lock actual OuterRect/WorkRect right-most position.\n\t// This is done late to handle the case of fixed-columns tables not claiming more widths that they need.\n\t// Because of this we are careful with uses of WorkRect and InnerClipRect before this point.\n\tif (table->RightMostStretchedColumn != -1)\n\t\ttable->Flags &= ~ImGuiTableFlags_NoHostExtendX;\n\tif (table->Flags & ImGuiTableFlags_NoHostExtendX)\n\t{\n\t\ttable->OuterRect.Max.x = table->WorkRect.Max.x = unused_x1;\n\t\ttable->InnerClipRect.Max.x = ImMin(table->InnerClipRect.Max.x, unused_x1);\n\t}\n\ttable->InnerWindow->ParentWorkRect = table->WorkRect;\n\ttable->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f);\n\ttable->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f);\n\n\t// Setup window's WorkRect.Max.y for GetContentRegionAvail(). Other values will be updated in each TableBeginCell() call.\n\tfloat window_content_max_y;\n\tif (table->Flags & ImGuiTableFlags_NoHostExtendY)\n\t\twindow_content_max_y = table->OuterRect.Max.y;\n\telse\n\t\twindow_content_max_y = ImMax(table->InnerWindow->ContentRegionRect.Max.y, (table->Flags & ImGuiTableFlags_ScrollY) ? 0.0f : table->OuterRect.Max.y);\n\ttable->InnerWindow->WorkRect.Max.y = ImClamp(window_content_max_y - g.Style.CellPadding.y, table->InnerWindow->WorkRect.Min.y, table->InnerWindow->WorkRect.Max.y);\n\n\t// [Part 9] Allocate draw channels and setup background cliprect\n\tTableSetupDrawChannels(table);\n\n\t// [Part 10] Hit testing on borders\n\tif (table->Flags & ImGuiTableFlags_Resizable)\n\t\tTableUpdateBorders(table);\n\ttable_instance->LastFirstRowHeight = 0.0f;\n\ttable->IsLayoutLocked = true;\n\ttable->IsUsingHeaders = false;\n\n\t// [Part 11] Context menu\n\tif (TableBeginContextMenuPopup(table))\n\t{\n\t\tTableDrawContextMenu(table);\n\t\tEndPopup();\n\t}\n\n\t// [Part 12] Sanitize and build sort specs before we have a chance to use them for display.\n\t// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)\n\tif (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable))\n\t\tTableSortSpecsBuild(table);\n\n\t// [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns)\n\tif (table->FreezeColumnsRequest > 0)\n\t\ttable->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x;\n\tif (table->FreezeRowsRequest > 0)\n\t\ttable->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight;\n\ttable_instance->LastFrozenHeight = 0.0f;\n\n\t// Initial state\n\tImGuiWindow* inner_window = table->InnerWindow;\n\tif (table->Flags & ImGuiTableFlags_NoClip)\n\t\ttable->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);\n\telse\n\t\tinner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);\n}\n\n// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()\n// - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise.\nvoid ImGui::TableUpdateBorders(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(table->Flags & ImGuiTableFlags_Resizable);\n\n\t// At this point OuterRect height may be zero or under actual final height, so we rely on temporal coherency and\n\t// use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not\n\t// really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height).\n\t// Actual columns highlight/render will be performed in EndTable() and not be affected.\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\tconst float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;\n\tconst float hit_y1 = table->OuterRect.Min.y;\n\tconst float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);\n\tconst float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight;\n\n\tfor (int order_n = 0; order_n < table->ColumnsCount; order_n++)\n\t{\n\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))\n\t\t\tcontinue;\n\n\t\tconst int column_n = table->DisplayOrderToIndex[order_n];\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_))\n\t\t\tcontinue;\n\n\t\t// ImGuiTableFlags_NoBordersInBodyUntilResize will be honored in TableDrawBorders()\n\t\tconst float border_y2_hit = (table->Flags & ImGuiTableFlags_NoBordersInBody) ? hit_y2_head : hit_y2_body;\n\t\tif ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false)\n\t\t\tcontinue;\n\n\t\tif (!column->IsVisibleX && table->LastResizedColumn != column_n)\n\t\t\tcontinue;\n\n\t\tImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent);\n\t\tImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit);\n\t\tItemAdd(hit_rect, column_id, NULL, ImGuiItemFlags_NoNav);\n\t\t//GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100));\n\n\t\tbool hovered = false, held = false;\n\t\tbool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus);\n\t\tif (pressed && IsMouseDoubleClicked(0))\n\t\t{\n\t\t\tTableSetColumnWidthAutoSingle(table, column_n);\n\t\t\tClearActiveID();\n\t\t\theld = hovered = false;\n\t\t}\n\t\tif (held)\n\t\t{\n\t\t\tif (table->LastResizedColumn == -1)\n\t\t\t\ttable->ResizeLockMinContentsX2 = table->RightMostEnabledColumn != -1 ? table->Columns[table->RightMostEnabledColumn].MaxX : -FLT_MAX;\n\t\t\ttable->ResizedColumn = (ImGuiTableColumnIdx)column_n;\n\t\t\ttable->InstanceInteracted = table->InstanceCurrent;\n\t\t}\n\t\tif ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held)\n\t\t{\n\t\t\ttable->HoveredColumnBorder = (ImGuiTableColumnIdx)column_n;\n\t\t\tSetMouseCursor(ImGuiMouseCursor_ResizeEW);\n\t\t}\n\t}\n}\n\nvoid    ImGui::EndTable()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && \"Only call EndTable() if BeginTable() returns true!\");\n\n\t// This assert would be very useful to catch a common error... unfortunately it would probably trigger in some\n\t// cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border)\n\t//IM_ASSERT(table->IsLayoutLocked && \"Table unused: never called TableNextRow(), is that the intent?\");\n\n\t// If the user never got to call TableNextRow() or TableNextColumn(), we call layout ourselves to ensure all our\n\t// code paths are consistent (instead of just hoping that TableBegin/TableEnd will work), get borders drawn, etc.\n\tif (!table->IsLayoutLocked)\n\t\tTableUpdateLayout(table);\n\n\tconst ImGuiTableFlags flags = table->Flags;\n\tImGuiWindow* inner_window = table->InnerWindow;\n\tImGuiWindow* outer_window = table->OuterWindow;\n\tImGuiTableTempData* temp_data = table->TempData;\n\tIM_ASSERT(inner_window == g.CurrentWindow);\n\tIM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow);\n\n\tif (table->IsInsideRow)\n\t\tTableEndRow(table);\n\n\t// Context menu in columns body\n\tif (flags & ImGuiTableFlags_ContextMenuInBody)\n\t\tif (table->HoveredColumnBody != -1 && !IsAnyItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))\n\t\t\tTableOpenContextMenu((int)table->HoveredColumnBody);\n\n\t// Finalize table height\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\tinner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;\n\tinner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;\n\tinner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;\n\tconst float inner_content_max_y = table->RowPosY2;\n\tIM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y);\n\tif (inner_window != outer_window)\n\t\tinner_window->DC.CursorMaxPos.y = inner_content_max_y;\n\telse if (!(flags & ImGuiTableFlags_NoHostExtendY))\n\t\ttable->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height\n\ttable->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);\n\ttable_instance->LastOuterHeight = table->OuterRect.GetHeight();\n\n\t// Setup inner scrolling range\n\t// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,\n\t// but since the later is likely to be impossible to do we'd rather update both axises together.\n\tif (table->Flags & ImGuiTableFlags_ScrollX)\n\t{\n\t\tconst float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;\n\t\tfloat max_pos_x = table->InnerWindow->DC.CursorMaxPos.x;\n\t\tif (table->RightMostEnabledColumn != -1)\n\t\t\tmax_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border);\n\t\tif (table->ResizedColumn != -1)\n\t\t\tmax_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2);\n\t\ttable->InnerWindow->DC.CursorMaxPos.x = max_pos_x;\n\t}\n\n\t// Pop clipping rect\n\tif (!(flags & ImGuiTableFlags_NoClip))\n\t\tinner_window->DrawList->PopClipRect();\n\tinner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back();\n\n\t// Draw borders\n\tif ((flags & ImGuiTableFlags_Borders) != 0)\n\t\tTableDrawBorders(table);\n\n#if 0\n\t// Strip out dummy channel draw calls\n\t// We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out)\n\t// Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway.\n\t// Cons: making it harder for users watching metrics/debugger to spot the wasted vertices.\n\tif (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1)\n\t{\n\t\tImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel];\n\t\tdummy_channel->_CmdBuffer.resize(0);\n\t\tdummy_channel->_IdxBuffer.resize(0);\n\t}\n#endif\n\n\t// Flatten channels and merge draw calls\n\tImDrawListSplitter* splitter = table->DrawSplitter;\n\tsplitter->SetCurrentChannel(inner_window->DrawList, 0);\n\tif ((table->Flags & ImGuiTableFlags_NoClip) == 0)\n\t\tTableMergeDrawChannels(table);\n\tsplitter->Merge(inner_window->DrawList);\n\n\t// Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable()\n\tfloat auto_fit_width_for_fixed = 0.0f;\n\tfloat auto_fit_width_for_stretched = 0.0f;\n\tfloat auto_fit_width_for_stretched_min = 0.0f;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\tif (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))\n\t\t{\n\t\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\t\tfloat column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);\n\t\t\tif (column->Flags & ImGuiTableColumnFlags_WidthFixed)\n\t\t\t\tauto_fit_width_for_fixed += column_width_request;\n\t\t\telse\n\t\t\t\tauto_fit_width_for_stretched += column_width_request;\n\t\t\tif ((column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->Flags & ImGuiTableColumnFlags_NoResize) != 0)\n\t\t\t\tauto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column->StretchWeight / table->ColumnsStretchSumWeights));\n\t\t}\n\tconst float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);\n\ttable->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min);\n\n\t// Update scroll\n\tif ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window)\n\t{\n\t\tinner_window->Scroll.x = 0.0f;\n\t}\n\telse if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent)\n\t{\n\t\t// When releasing a column being resized, scroll to keep the resulting column in sight\n\t\tconst float neighbor_width_to_keep_visible = table->MinColumnWidth + table->CellPaddingX * 2.0f;\n\t\tImGuiTableColumn* column = &table->Columns[table->LastResizedColumn];\n\t\tif (column->MaxX < table->InnerClipRect.Min.x)\n\t\t\tSetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - neighbor_width_to_keep_visible, 1.0f);\n\t\telse if (column->MaxX > table->InnerClipRect.Max.x)\n\t\t\tSetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + neighbor_width_to_keep_visible, 1.0f);\n\t}\n\n\t// Apply resizing/dragging at the end of the frame\n\tif (table->ResizedColumn != -1 && table->InstanceCurrent == table->InstanceInteracted)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[table->ResizedColumn];\n\t\tconst float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS);\n\t\tconst float new_width = ImFloor(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f);\n\t\ttable->ResizedColumnNextWidth = new_width;\n\t}\n\n\t// Pop from id stack\n\tIM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, \"Mismatching PushID/PopID!\");\n\tIM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, \"Too many PopItemWidth!\");\n\tif (table->InstanceCurrent > 0)\n\t\tPopID();\n\tPopID();\n\n\t// Restore window data that we modified\n\tconst ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos;\n\tinner_window->WorkRect = temp_data->HostBackupWorkRect;\n\tinner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect;\n\tinner_window->SkipItems = table->HostSkipItems;\n\touter_window->DC.CursorPos = table->OuterRect.Min;\n\touter_window->DC.ItemWidth = temp_data->HostBackupItemWidth;\n\touter_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize;\n\touter_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset;\n\n\t// Layout in outer window\n\t// (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding\n\t// CursorPosPrevLine and CursorMaxPos manually. That should be a more general layout feature, see same problem e.g. #3414)\n\tif (inner_window != outer_window)\n\t{\n\t\tEndChild();\n\t}\n\telse\n\t{\n\t\tItemSize(table->OuterRect.GetSize());\n\t\tItemAdd(table->OuterRect, 0);\n\t}\n\n\t// Override declared contents width/height to enable auto-resize while not needlessly adding a scrollbar\n\tif (table->Flags & ImGuiTableFlags_NoHostExtendX)\n\t{\n\t\t// FIXME-TABLE: Could we remove this section?\n\t\t// ColumnsAutoFitWidth may be one frame ahead here since for Fixed+NoResize is calculated from latest contents\n\t\tIM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0);\n\t\touter_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth);\n\t}\n\telse if (temp_data->UserOuterSize.x <= 0.0f)\n\t{\n\t\tconst float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f;\n\t\touter_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x);\n\t\touter_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth));\n\t}\n\telse\n\t{\n\t\touter_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x);\n\t}\n\tif (temp_data->UserOuterSize.y <= 0.0f)\n\t{\n\t\tconst float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f;\n\t\touter_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y);\n\t\touter_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y));\n\t}\n\telse\n\t{\n\t\t// OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags_NoHostExtendY is set)\n\t\touter_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table->OuterRect.Max.y);\n\t}\n\n\t// Save settings\n\tif (table->IsSettingsDirty)\n\t\tTableSaveSettings(table);\n\ttable->IsInitializing = false;\n\n\t// Clear or restore current table, if any\n\tIM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);\n\tIM_ASSERT(g.TablesTempDataStacked > 0);\n\ttemp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL;\n\tg.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL;\n\tif (g.CurrentTable)\n\t{\n\t\tg.CurrentTable->TempData = temp_data;\n\t\tg.CurrentTable->DrawSplitter = &temp_data->DrawSplitter;\n\t}\n\touter_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1;\n\tNavUpdateCurrentWindowIsScrollPushableX();\n}\n\n// See \"COLUMN SIZING POLICIES\" comments at the top of this file\n// If (init_width_or_weight <= 0.0f) it is ignored\nvoid ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && \"Need to call TableSetupColumn() after BeginTable()!\");\n\tIM_ASSERT(table->IsLayoutLocked == false && \"Need to call call TableSetupColumn() before first row!\");\n\tIM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && \"Illegal to pass StatusMask values to TableSetupColumn()\");\n\tif (table->DeclColumnsCount >= table->ColumnsCount)\n\t{\n\t\tIM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, \"Called TableSetupColumn() too many times!\");\n\t\treturn;\n\t}\n\n\tImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount];\n\ttable->DeclColumnsCount++;\n\n\t// Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa.\n\t// Give a grace to users of ImGuiTableFlags_ScrollX.\n\tif (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0)\n\t\tIM_ASSERT(init_width_or_weight <= 0.0f && \"Can only specify width/weight if sizing policy is set explicitly in either Table or Column.\");\n\n\t// When passing a width automatically enforce WidthFixed policy\n\t// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)\n\tif ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)\n\t\tif ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)\n\t\t\tflags |= ImGuiTableColumnFlags_WidthFixed;\n\n\tTableSetupColumnFlags(table, column, flags);\n\tcolumn->UserID = user_id;\n\tflags = column->Flags;\n\n\t// Initialize defaults\n\tcolumn->InitStretchWeightOrWidth = init_width_or_weight;\n\tif (table->IsInitializing)\n\t{\n\t\t// Init width or weight\n\t\tif (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)\n\t\t{\n\t\t\tif ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)\n\t\t\t\tcolumn->WidthRequest = init_width_or_weight;\n\t\t\tif (flags & ImGuiTableColumnFlags_WidthStretch)\n\t\t\t\tcolumn->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;\n\n\t\t\t// Disable auto-fit if an explicit width/weight has been specified\n\t\t\tif (init_width_or_weight > 0.0f)\n\t\t\t\tcolumn->AutoFitQueue = 0x00;\n\t\t}\n\n\t\t// Init default visibility/sort state\n\t\tif ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)\n\t\t\tcolumn->IsUserEnabled = column->IsUserEnabledNextFrame = false;\n\t\tif (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)\n\t\t{\n\t\t\tcolumn->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.\n\t\t\tcolumn->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);\n\t\t}\n\t}\n\n\t// Store name (append with zero-terminator in contiguous buffer)\n\tcolumn->NameOffset = -1;\n\tif (label != NULL && label[0] != 0)\n\t{\n\t\tcolumn->NameOffset = (ImS16)table->ColumnsNames.size();\n\t\ttable->ColumnsNames.append(label, label + strlen(label) + 1);\n\t}\n}\n\n// [Public]\nvoid ImGui::TableSetupScrollFreeze(int columns, int rows)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && \"Need to call TableSetupColumn() after BeginTable()!\");\n\tIM_ASSERT(table->IsLayoutLocked == false && \"Need to call TableSetupColumn() before first row!\");\n\tIM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);\n\tIM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit\n\n\ttable->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0;\n\ttable->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;\n\ttable->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;\n\ttable->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;\n\ttable->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b\n\n\t// Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered.\n\t// FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section)\n\tfor (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++)\n\t{\n\t\tint order_n = table->DisplayOrderToIndex[column_n];\n\t\tif (order_n != column_n && order_n >= table->FreezeColumnsRequest)\n\t\t{\n\t\t\tImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder);\n\t\t\tImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]);\n\t\t}\n\t}\n}\n\n//-----------------------------------------------------------------------------\n// [SECTION] Tables: Simple accessors\n//-----------------------------------------------------------------------------\n// - TableGetColumnCount()\n// - TableGetColumnName()\n// - TableGetColumnName() [Internal]\n// - TableSetColumnEnabled()\n// - TableGetColumnFlags()\n// - TableGetCellBgRect() [Internal]\n// - TableGetColumnResizeID() [Internal]\n// - TableGetHoveredColumn() [Internal]\n// - TableGetHoveredRow() [Internal]\n// - TableSetBgColor()\n//-----------------------------------------------------------------------------\n\nint ImGui::TableGetColumnCount()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\treturn table ? table->ColumnsCount : 0;\n}\n\nconst char* ImGui::TableGetColumnName(int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn NULL;\n\tif (column_n < 0)\n\t\tcolumn_n = table->CurrentColumn;\n\treturn TableGetColumnName(table, column_n);\n}\n\nconst char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)\n{\n\tif (table->IsLayoutLocked == false && column_n >= table->DeclColumnsCount)\n\t\treturn \"\"; // NameOffset is invalid at this point\n\tconst ImGuiTableColumn* column = &table->Columns[column_n];\n\tif (column->NameOffset == -1)\n\t\treturn \"\";\n\treturn &table->ColumnsNames.Buf[column->NameOffset];\n}\n\n// Change user accessible enabled/disabled state of a column (often perceived as \"showing/hiding\" from users point of view)\n// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)\n// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state.\n// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable().\n// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0.\n// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu.\nvoid ImGui::TableSetColumnEnabled(int column_n, bool enabled)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL);\n\tif (!table)\n\t\treturn;\n\tIM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above\n\tif (column_n < 0)\n\t\tcolumn_n = table->CurrentColumn;\n\tIM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);\n\tImGuiTableColumn* column = &table->Columns[column_n];\n\tcolumn->IsUserEnabledNextFrame = enabled;\n}\n\n// We allow querying for an extra column in order to poll the IsHovered state of the right-most section\nImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn ImGuiTableColumnFlags_None;\n\tif (column_n < 0)\n\t\tcolumn_n = table->CurrentColumn;\n\tif (column_n == table->ColumnsCount)\n\t\treturn (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None;\n\treturn table->Columns[column_n].Flags;\n}\n\n// Return the cell rectangle based on currently known height.\n// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.\n//   The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height.\n// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right\n//   columns report a small offset so their CellBgRect can extend up to the outer border.\n//   FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling.\nImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)\n{\n\tconst ImGuiTableColumn* column = &table->Columns[column_n];\n\tfloat x1 = column->MinX;\n\tfloat x2 = column->MaxX;\n\t//if (column->PrevEnabledColumn == -1)\n\t//    x1 -= table->OuterPaddingX;\n\t//if (column->NextEnabledColumn == -1)\n\t//    x2 += table->OuterPaddingX;\n\tx1 = ImMax(x1, table->WorkRect.Min.x);\n\tx2 = ImMin(x2, table->WorkRect.Max.x);\n\treturn ImRect(x1, table->RowPosY1, x2, table->RowPosY2);\n}\n\n// Return the resizing ID for the right-side of the given column.\nImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no)\n{\n\tIM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);\n\tImGuiID instance_id = TableGetInstanceID(table, instance_no);\n\treturn instance_id + 1 + column_n; // FIXME: #6140: still not ideal\n}\n\n// Return -1 when table is not hovered. return columns_count if hovering the unused space at the right of the right-most visible column.\nint ImGui::TableGetHoveredColumn()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn -1;\n\treturn (int)table->HoveredColumnBody;\n}\n\n// Return -1 when table is not hovered. Return maxrow+1 if in table but below last submitted row.\n// *IMPORTANT* Unlike TableGetHoveredColumn(), this has a one frame latency in updating the value.\n// This difference with is the reason why this is not public yet.\nint ImGui::TableGetHoveredRow()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn -1;\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\treturn (int)table_instance->HoveredRowLast;\n}\n\nvoid ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(target != ImGuiTableBgTarget_None);\n\n\tif (color == IM_COL32_DISABLE)\n\t\tcolor = 0;\n\n\t// We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time.\n\tswitch (target)\n\t{\n\tcase ImGuiTableBgTarget_CellBg:\n\t{\n\t\tif (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard\n\t\t\treturn;\n\t\tif (column_n == -1)\n\t\t\tcolumn_n = table->CurrentColumn;\n\t\tif (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))\n\t\t\treturn;\n\t\tif (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)\n\t\t\ttable->RowCellDataCurrent++;\n\t\tImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent];\n\t\tcell_data->BgColor = color;\n\t\tcell_data->Column = (ImGuiTableColumnIdx)column_n;\n\t\tbreak;\n\t}\n\tcase ImGuiTableBgTarget_RowBg0:\n\tcase ImGuiTableBgTarget_RowBg1:\n\t{\n\t\tif (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard\n\t\t\treturn;\n\t\tIM_ASSERT(column_n == -1);\n\t\tint bg_idx = (target == ImGuiTableBgTarget_RowBg1) ? 1 : 0;\n\t\ttable->RowBgColor[bg_idx] = color;\n\t\tbreak;\n\t}\n\tdefault:\n\t\tIM_ASSERT(0);\n\t}\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Row changes\n//-------------------------------------------------------------------------\n// - TableGetRowIndex()\n// - TableNextRow()\n// - TableBeginRow() [Internal]\n// - TableEndRow() [Internal]\n//-------------------------------------------------------------------------\n\n// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows\nint ImGui::TableGetRowIndex()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn 0;\n\treturn table->CurrentRow;\n}\n\n// [Public] Starts into the first cell of a new row\nvoid ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\n\tif (!table->IsLayoutLocked)\n\t\tTableUpdateLayout(table);\n\tif (table->IsInsideRow)\n\t\tTableEndRow(table);\n\n\ttable->LastRowFlags = table->RowFlags;\n\ttable->RowFlags = row_flags;\n\ttable->RowCellPaddingY = g.Style.CellPadding.y;\n\ttable->RowMinHeight = row_min_height;\n\tTableBeginRow(table);\n\n\t// We honor min_row_height requested by user, but cannot guarantee per-row maximum height,\n\t// because that would essentially require a unique clipping rectangle per-cell.\n\ttable->RowPosY2 += table->RowCellPaddingY * 2.0f;\n\ttable->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height);\n\n\t// Disable output until user calls TableNextColumn()\n\ttable->InnerWindow->SkipItems = true;\n}\n\n// [Internal] Only called by TableNextRow()\nvoid ImGui::TableBeginRow(ImGuiTable* table)\n{\n\tImGuiWindow* window = table->InnerWindow;\n\tIM_ASSERT(!table->IsInsideRow);\n\n\t// New row\n\ttable->CurrentRow++;\n\ttable->CurrentColumn = -1;\n\ttable->RowBgColor[0] = table->RowBgColor[1] = IM_COL32_DISABLE;\n\ttable->RowCellDataCurrent = -1;\n\ttable->IsInsideRow = true;\n\n\t// Begin frozen rows\n\tfloat next_y1 = table->RowPosY2;\n\tif (table->CurrentRow == 0 && table->FreezeRowsCount > 0)\n\t\tnext_y1 = window->DC.CursorPos.y = table->OuterRect.Min.y;\n\n\ttable->RowPosY1 = table->RowPosY2 = next_y1;\n\ttable->RowTextBaseline = 0.0f;\n\ttable->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent\n\n\twindow->DC.PrevLineTextBaseOffset = 0.0f;\n\twindow->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + table->RowCellPaddingY); // This allows users to call SameLine() to share LineSize between columns.\n\twindow->DC.PrevLineSize = window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); // This allows users to call SameLine() to share LineSize between columns, and to call it from first column too.\n\twindow->DC.IsSameLine = window->DC.IsSetPos = false;\n\twindow->DC.CursorMaxPos.y = next_y1;\n\n\t// Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging.\n\tif (table->RowFlags & ImGuiTableRowFlags_Headers)\n\t{\n\t\tTableSetBgColor(ImGuiTableBgTarget_RowBg0, GetColorU32(ImGuiCol_TableHeaderBg));\n\t\tif (table->CurrentRow == 0)\n\t\t\ttable->IsUsingHeaders = true;\n\t}\n}\n\n// [Internal] Called by TableNextRow()\nvoid ImGui::TableEndRow(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(window == table->InnerWindow);\n\tIM_ASSERT(table->IsInsideRow);\n\n\tif (table->CurrentColumn != -1)\n\t\tTableEndCell(table);\n\n\t// Logging\n\tif (g.LogEnabled)\n\t\tLogRenderedText(NULL, \"|\");\n\n\t// Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is\n\t// likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding.\n\twindow->DC.CursorPos.y = table->RowPosY2;\n\n\t// Row background fill\n\tconst float bg_y1 = table->RowPosY1;\n\tconst float bg_y2 = table->RowPosY2;\n\tconst bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);\n\tconst bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);\n\tif (table->CurrentRow == 0)\n\t\tTableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1;\n\n\tconst bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);\n\tif (is_visible)\n\t{\n\t\t// Update data for TableGetHoveredRow()\n\t\tif (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2)\n\t\t\tTableGetInstanceData(table, table->InstanceCurrent)->HoveredRowNext = table->CurrentRow;\n\n\t\t// Decide of background color for the row\n\t\tImU32 bg_col0 = 0;\n\t\tImU32 bg_col1 = 0;\n\t\tif (table->RowBgColor[0] != IM_COL32_DISABLE)\n\t\t\tbg_col0 = table->RowBgColor[0];\n\t\telse if (table->Flags & ImGuiTableFlags_RowBg)\n\t\t\tbg_col0 = GetColorU32((table->RowBgColorCounter & 1) ? ImGuiCol_TableRowBgAlt : ImGuiCol_TableRowBg);\n\t\tif (table->RowBgColor[1] != IM_COL32_DISABLE)\n\t\t\tbg_col1 = table->RowBgColor[1];\n\n\t\t// Decide of top border color\n\t\tImU32 border_col = 0;\n\t\tconst float border_size = TABLE_BORDER_SIZE;\n\t\tif (table->CurrentRow > 0 || table->InnerWindow == table->OuterWindow)\n\t\t\tif (table->Flags & ImGuiTableFlags_BordersInnerH)\n\t\t\t\tborder_col = (table->LastRowFlags & ImGuiTableRowFlags_Headers) ? table->BorderColorStrong : table->BorderColorLight;\n\n\t\tconst bool draw_cell_bg_color = table->RowCellDataCurrent >= 0;\n\t\tconst bool draw_strong_bottom_border = unfreeze_rows_actual;\n\t\tif ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color)\n\t\t{\n\t\t\t// In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is\n\t\t\t// always followed by a change of clipping rectangle we perform the smallest overwrite possible here.\n\t\t\tif ((table->Flags & ImGuiTableFlags_NoClip) == 0)\n\t\t\t\twindow->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4();\n\t\t\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0);\n\t\t}\n\n\t\t// Draw row background\n\t\t// We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle\n\t\tif (bg_col0 || bg_col1)\n\t\t{\n\t\t\tImRect row_rect(table->WorkRect.Min.x, bg_y1, table->WorkRect.Max.x, bg_y2);\n\t\t\trow_rect.ClipWith(table->BgClipRect);\n\t\t\tif (bg_col0 != 0 && row_rect.Min.y < row_rect.Max.y)\n\t\t\t\twindow->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col0);\n\t\t\tif (bg_col1 != 0 && row_rect.Min.y < row_rect.Max.y)\n\t\t\t\twindow->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col1);\n\t\t}\n\n\t\t// Draw cell background color\n\t\tif (draw_cell_bg_color)\n\t\t{\n\t\t\tImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent];\n\t\t\tfor (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++)\n\t\t\t{\n\t\t\t\t// As we render the BG here we need to clip things (for layout we would not)\n\t\t\t\t// FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling.\n\t\t\t\tconst ImGuiTableColumn* column = &table->Columns[cell_data->Column];\n\t\t\t\tImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column);\n\t\t\t\tcell_bg_rect.ClipWith(table->BgClipRect);\n\t\t\t\tcell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x);     // So that first column after frozen one gets clipped when scrolling\n\t\t\t\tcell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX);\n\t\t\t\twindow->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor);\n\t\t\t}\n\t\t}\n\n\t\t// Draw top border\n\t\tif (border_col && bg_y1 >= table->BgClipRect.Min.y && bg_y1 < table->BgClipRect.Max.y)\n\t\t\twindow->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), border_col, border_size);\n\n\t\t// Draw bottom border at the row unfreezing mark (always strong)\n\t\tif (draw_strong_bottom_border && bg_y2 >= table->BgClipRect.Min.y && bg_y2 < table->BgClipRect.Max.y)\n\t\t\twindow->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong, border_size);\n\t}\n\n\t// End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle)\n\t// We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and\n\t// get the new cursor position.\n\tif (unfreeze_rows_request)\n\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\ttable->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;\n\tif (unfreeze_rows_actual)\n\t{\n\t\tIM_ASSERT(table->IsUnfrozenRows == false);\n\t\tconst float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);\n\t\ttable->IsUnfrozenRows = true;\n\t\tTableGetInstanceData(table, table->InstanceCurrent)->LastFrozenHeight = y0 - table->OuterRect.Min.y;\n\n\t\t// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect\n\t\ttable->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);\n\t\ttable->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y;\n\t\ttable->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;\n\t\tIM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);\n\n\t\tfloat row_height = table->RowPosY2 - table->RowPosY1;\n\t\ttable->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;\n\t\ttable->RowPosY1 = table->RowPosY2 - row_height;\n\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t{\n\t\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\t\tcolumn->DrawChannelCurrent = column->DrawChannelUnfrozen;\n\t\t\tcolumn->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;\n\t\t}\n\n\t\t// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y\n\t\tSetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);\n\t\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);\n\t}\n\n\tif (!(table->RowFlags & ImGuiTableRowFlags_Headers))\n\t\ttable->RowBgColorCounter++;\n\ttable->IsInsideRow = false;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Columns changes\n//-------------------------------------------------------------------------\n// - TableGetColumnIndex()\n// - TableSetColumnIndex()\n// - TableNextColumn()\n// - TableBeginCell() [Internal]\n// - TableEndCell() [Internal]\n//-------------------------------------------------------------------------\n\nint ImGui::TableGetColumnIndex()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn 0;\n\treturn table->CurrentColumn;\n}\n\n// [Public] Append into a specific column\nbool ImGui::TableSetColumnIndex(int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn false;\n\n\tif (table->CurrentColumn != column_n)\n\t{\n\t\tif (table->CurrentColumn != -1)\n\t\t\tTableEndCell(table);\n\t\tIM_ASSERT(column_n >= 0 && table->ColumnsCount);\n\t\tTableBeginCell(table, column_n);\n\t}\n\n\t// Return whether the column is visible. User may choose to skip submitting items based on this return value,\n\t// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.\n\treturn table->Columns[column_n].IsRequestOutput;\n}\n\n// [Public] Append into the next column, wrap and create a new row when already on last column\nbool ImGui::TableNextColumn()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (!table)\n\t\treturn false;\n\n\tif (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount)\n\t{\n\t\tif (table->CurrentColumn != -1)\n\t\t\tTableEndCell(table);\n\t\tTableBeginCell(table, table->CurrentColumn + 1);\n\t}\n\telse\n\t{\n\t\tTableNextRow();\n\t\tTableBeginCell(table, 0);\n\t}\n\n\t// Return whether the column is visible. User may choose to skip submitting items based on this return value,\n\t// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.\n\treturn table->Columns[table->CurrentColumn].IsRequestOutput;\n}\n\n// [Internal] Called by TableSetColumnIndex()/TableNextColumn()\n// This is called very frequently, so we need to be mindful of unnecessary overhead.\n// FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns.\nvoid ImGui::TableBeginCell(ImGuiTable* table, int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTableColumn* column = &table->Columns[column_n];\n\tImGuiWindow* window = table->InnerWindow;\n\ttable->CurrentColumn = column_n;\n\n\t// Start position is roughly ~~ CellRect.Min + CellPadding + Indent\n\tfloat start_x = column->WorkMinX;\n\tif (column->Flags & ImGuiTableColumnFlags_IndentEnable)\n\t\tstart_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row.\n\n\twindow->DC.CursorPos.x = start_x;\n\twindow->DC.CursorPos.y = table->RowPosY1 + table->RowCellPaddingY;\n\twindow->DC.CursorMaxPos.x = window->DC.CursorPos.x;\n\twindow->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT\n\twindow->DC.CursorPosPrevLine.x = window->DC.CursorPos.x; // PrevLine.y is preserved. This allows users to call SameLine() to share LineSize between columns.\n\twindow->DC.CurrLineTextBaseOffset = table->RowTextBaseline;\n\twindow->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent;\n\n\t// Note how WorkRect.Max.y is only set once during layout\n\twindow->WorkRect.Min.y = window->DC.CursorPos.y;\n\twindow->WorkRect.Min.x = column->WorkMinX;\n\twindow->WorkRect.Max.x = column->WorkMaxX;\n\twindow->DC.ItemWidth = column->ItemWidth;\n\n\twindow->SkipItems = column->IsSkipItems;\n\tif (column->IsSkipItems)\n\t{\n\t\tg.LastItemData.ID = 0;\n\t\tg.LastItemData.StatusFlags = 0;\n\t}\n\n\tif (table->Flags & ImGuiTableFlags_NoClip)\n\t{\n\t\t// FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.\n\t\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);\n\t\t//IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP);\n\t}\n\telse\n\t{\n\t\t// FIXME-TABLE: Could avoid this if draw channel is dummy channel?\n\t\tSetWindowClipRectBeforeSetChannel(window, column->ClipRect);\n\t\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);\n\t}\n\n\t// Logging\n\tif (g.LogEnabled && !column->IsSkipItems)\n\t{\n\t\tLogRenderedText(&window->DC.CursorPos, \"|\");\n\t\tg.LogLinePosY = FLT_MAX;\n\t}\n}\n\n// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn()\nvoid ImGui::TableEndCell(ImGuiTable* table)\n{\n\tImGuiTableColumn* column = &table->Columns[table->CurrentColumn];\n\tImGuiWindow* window = table->InnerWindow;\n\n\tif (window->DC.IsSetPos)\n\t\tErrorCheckUsingSetCursorPosToExtendParentBoundaries();\n\n\t// Report maximum position so we can infer content size per column.\n\tfloat* p_max_pos_x;\n\tif (table->RowFlags & ImGuiTableRowFlags_Headers)\n\t\tp_max_pos_x = &column->ContentMaxXHeadersUsed;  // Useful in case user submit contents in header row that is not a TableHeader() call\n\telse\n\t\tp_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen;\n\t*p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x);\n\tif (column->IsEnabled)\n\t\ttable->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->RowCellPaddingY);\n\tcolumn->ItemWidth = window->DC.ItemWidth;\n\n\t// Propagate text baseline for the entire row\n\t// FIXME-TABLE: Here we propagate text baseline from the last line of the cell.. instead of the first one.\n\ttable->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Columns width management\n//-------------------------------------------------------------------------\n// - TableGetMaxColumnWidth() [Internal]\n// - TableGetColumnWidthAuto() [Internal]\n// - TableSetColumnWidth()\n// - TableSetColumnWidthAutoSingle() [Internal]\n// - TableSetColumnWidthAutoAll() [Internal]\n// - TableUpdateColumnsWeightFromWidth() [Internal]\n//-------------------------------------------------------------------------\n\n// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.\nfloat ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)\n{\n\tconst ImGuiTableColumn* column = &table->Columns[column_n];\n\tfloat max_width = FLT_MAX;\n\tconst float min_column_distance = table->MinColumnWidth + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2;\n\tif (table->Flags & ImGuiTableFlags_ScrollX)\n\t{\n\t\t// Frozen columns can't reach beyond visible width else scrolling will naturally break.\n\t\t// (we use DisplayOrder as within a set of multiple frozen column reordering is possible)\n\t\tif (column->DisplayOrder < table->FreezeColumnsRequest)\n\t\t{\n\t\t\tmax_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX;\n\t\t\tmax_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2;\n\t\t}\n\t}\n\telse if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0)\n\t{\n\t\t// If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make\n\t\t// sure they are all visible. Because of this we also know that all of the columns will always fit in\n\t\t// table->WorkRect and therefore in table->InnerRect (because ScrollX is off)\n\t\t// FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match.\n\t\t// See \"table_width_distrib\" and \"table_width_keep_visible\" tests\n\t\tmax_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX;\n\t\t//max_width -= table->CellSpacingX1;\n\t\tmax_width -= table->CellSpacingX2;\n\t\tmax_width -= table->CellPaddingX * 2.0f;\n\t\tmax_width -= table->OuterPaddingX;\n\t}\n\treturn max_width;\n}\n\n// Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field\nfloat ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column)\n{\n\tconst float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX;\n\tconst float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX;\n\tfloat width_auto = content_width_body;\n\tif (!(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth))\n\t\twidth_auto = ImMax(width_auto, content_width_headers);\n\n\t// Non-resizable fixed columns preserve their requested width\n\tif ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f)\n\t\tif (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize))\n\t\t\twidth_auto = column->InitStretchWeightOrWidth;\n\n\treturn ImMax(width_auto, table->MinColumnWidth);\n}\n\n// 'width' = inner column width, without padding\nvoid ImGui::TableSetColumnWidth(int column_n, float width)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && table->IsLayoutLocked == false);\n\tIM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);\n\tImGuiTableColumn* column_0 = &table->Columns[column_n];\n\tfloat column_0_width = width;\n\n\t// Apply constraints early\n\t// Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)\n\tIM_ASSERT(table->MinColumnWidth > 0.0f);\n\tconst float min_width = table->MinColumnWidth;\n\tconst float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n));\n\tcolumn_0_width = ImClamp(column_0_width, min_width, max_width);\n\tif (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)\n\t\treturn;\n\n\t//IMGUI_DEBUG_PRINT(\"TableSetColumnWidth(%d, %.1f->%.1f)\\n\", column_0_idx, column_0->WidthGiven, column_0_width);\n\tImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;\n\n\t// In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns.\n\t// - All fixed: easy.\n\t// - All stretch: easy.\n\t// - One or more fixed + one stretch: easy.\n\t// - One or more fixed + more than one stretch: tricky.\n\t// Qt when manual resize is enabled only supports a single _trailing_ stretch column, we support more cases here.\n\n\t// When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1.\n\t// FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user.\n\t// Scenarios:\n\t// - F1 F2 F3  resize from F1| or F2|   --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset.\n\t// - F1 F2 F3  resize from F3|          --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered.\n\t// - F1 F2 W3  resize from F1| or F2|   --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size.\n\t// - F1 F2 W3  resize from W3|          --> ok: no-op (disabled by Resize Rule 1)\n\t// - W1 W2 W3  resize from W1| or W2|   --> ok\n\t// - W1 W2 W3  resize from W3|          --> ok: no-op (disabled by Resize Rule 1)\n\t// - W1 F2 F3  resize from F3|          --> ok: no-op (disabled by Resize Rule 1)\n\t// - W1 F2     resize from F2|          --> ok: no-op (disabled by Resize Rule 1)\n\t// - W1 W2 F3  resize from W1| or W2|   --> ok\n\t// - W1 F2 W3  resize from W1| or F2|   --> ok\n\t// - F1 W2 F3  resize from W2|          --> ok\n\t// - F1 W3 F2  resize from W3|          --> ok\n\t// - W1 F2 F3  resize from W1|          --> ok: equivalent to resizing |F2. F3 will not move.\n\t// - W1 F2 F3  resize from F2|          --> ok\n\t// All resizes from a Wx columns are locking other columns.\n\n\t// Possible improvements:\n\t// - W1 W2 W3  resize W1|               --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns.\n\t// - W3 F1 F2  resize W3|               --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix.\n\n\t// [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout().\n\n\t// If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize.\n\t// This is the preferred resize path\n\tif (column_0->Flags & ImGuiTableColumnFlags_WidthFixed)\n\t\tif (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder)\n\t\t{\n\t\t\tcolumn_0->WidthRequest = column_0_width;\n\t\t\ttable->IsSettingsDirty = true;\n\t\t\treturn;\n\t\t}\n\n\t// We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column)\n\tif (column_1 == NULL)\n\t\tcolumn_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL;\n\tif (column_1 == NULL)\n\t\treturn;\n\n\t// Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column.\n\t// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)\n\tfloat column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);\n\tcolumn_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;\n\tIM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f);\n\tcolumn_0->WidthRequest = column_0_width;\n\tcolumn_1->WidthRequest = column_1_width;\n\tif ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch)\n\t\tTableUpdateColumnsWeightFromWidth(table);\n\ttable->IsSettingsDirty = true;\n}\n\n// Disable clipping then auto-fit, will take 2 frames\n// (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns)\nvoid ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n)\n{\n\t// Single auto width uses auto-fit\n\tImGuiTableColumn* column = &table->Columns[column_n];\n\tif (!column->IsEnabled)\n\t\treturn;\n\tcolumn->CannotSkipItemsQueue = (1 << 0);\n\ttable->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n;\n}\n\nvoid ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table)\n{\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column\n\t\t\tcontinue;\n\t\tcolumn->CannotSkipItemsQueue = (1 << 0);\n\t\tcolumn->AutoFitQueue = (1 << 1);\n\t}\n}\n\nvoid ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table)\n{\n\tIM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1);\n\n\t// Measure existing quantities\n\tfloat visible_weight = 0.0f;\n\tfloat visible_width = 0.0f;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))\n\t\t\tcontinue;\n\t\tIM_ASSERT(column->StretchWeight > 0.0f);\n\t\tvisible_weight += column->StretchWeight;\n\t\tvisible_width += column->WidthRequest;\n\t}\n\tIM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f);\n\n\t// Apply new weights\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))\n\t\t\tcontinue;\n\t\tcolumn->StretchWeight = (column->WidthRequest / visible_width) * visible_weight;\n\t\tIM_ASSERT(column->StretchWeight > 0.0f);\n\t}\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Drawing\n//-------------------------------------------------------------------------\n// - TablePushBackgroundChannel() [Internal]\n// - TablePopBackgroundChannel() [Internal]\n// - TableSetupDrawChannels() [Internal]\n// - TableMergeDrawChannels() [Internal]\n// - TableDrawBorders() [Internal]\n//-------------------------------------------------------------------------\n\n// Bg2 is used by Selectable (and possibly other widgets) to render to the background.\n// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect.\nvoid ImGui::TablePushBackgroundChannel()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiTable* table = g.CurrentTable;\n\n\t// Optimization: avoid SetCurrentChannel() + PushClipRect()\n\ttable->HostBackupInnerClipRect = window->ClipRect;\n\tSetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd);\n\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent);\n}\n\nvoid ImGui::TablePopBackgroundChannel()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiTable* table = g.CurrentTable;\n\tImGuiTableColumn* column = &table->Columns[table->CurrentColumn];\n\n\t// Optimization: avoid PopClipRect() + SetCurrentChannel()\n\tSetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect);\n\ttable->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);\n}\n\n// Allocate draw channels. Called by TableUpdateLayout()\n// - We allocate them following storage order instead of display order so reordering columns won't needlessly\n//   increase overall dormant memory cost.\n// - We isolate headers draw commands in their own channels instead of just altering clip rects.\n//   This is in order to facilitate merging of draw commands.\n// - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels.\n// - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other\n//   channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged.\n// - We allocate 1 or 2 background draw channels. This is because we know TablePushBackgroundChannel() is only used for\n//   horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4).\n// Draw channel allocation (before merging):\n// - NoClip                       --> 2+D+1 channels: bg0/1 + bg2 + foreground (same clip rect == always 1 draw call)\n// - Clip                         --> 2+D+N channels\n// - FreezeRows                   --> 2+D+N*2 (unless scrolling value is zero)\n// - FreezeRows || FreezeColunns  --> 3+D+N*2 (unless scrolling value is zero)\n// Where D is 1 if any column is clipped or hidden (dummy channel) otherwise 0.\nvoid ImGui::TableSetupDrawChannels(ImGuiTable* table)\n{\n\tconst int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1;\n\tconst int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount;\n\tconst int channels_for_bg = 1 + 1 * freeze_row_multiplier;\n\tconst int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0;\n\tconst int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;\n\ttable->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total);\n\ttable->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1);\n\ttable->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN;\n\ttable->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN);\n\n\tint draw_channel_current = 2;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (column->IsVisibleX && column->IsVisibleY)\n\t\t{\n\t\t\tcolumn->DrawChannelFrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current);\n\t\t\tcolumn->DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row + 1 : 0));\n\t\t\tif (!(table->Flags & ImGuiTableFlags_NoClip))\n\t\t\t\tdraw_channel_current++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcolumn->DrawChannelFrozen = column->DrawChannelUnfrozen = table->DummyDrawChannel;\n\t\t}\n\t\tcolumn->DrawChannelCurrent = column->DrawChannelFrozen;\n\t}\n\n\t// Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default.\n\t// All our cell highlight are manually clipped with BgClipRect. When unfreezing it will be made smaller to fit scrolling rect.\n\t// (This technically isn't part of setting up draw channels, but is reasonably related to be done here)\n\ttable->BgClipRect = table->InnerClipRect;\n\ttable->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect;\n\ttable->Bg2ClipRectForDrawCmd = table->HostClipRect;\n\tIM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y);\n}\n\n// This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable().\n// For simplicity we call it TableMergeDrawChannels() but in fact it only reorder channels + overwrite ClipRect,\n// actual merging is done by table->DrawSplitter.Merge() which is called right after TableMergeDrawChannels().\n//\n// Columns where the contents didn't stray off their local clip rectangle can be merged. To achieve\n// this we merge their clip rect and make them contiguous in the channel list, so they can be merged\n// by the call to DrawSplitter.Merge() following to the call to this function.\n// We reorder draw commands by arranging them into a maximum of 4 distinct groups:\n//\n//   1 group:               2 groups:              2 groups:              4 groups:\n//   [ 0. ] no freeze       [ 0. ] row freeze      [ 01 ] col freeze      [ 01 ] row+col freeze\n//   [ .. ]  or no scroll   [ 2. ]  and v-scroll   [ .. ]  and h-scroll   [ 23 ]  and v+h-scroll\n//\n// Each column itself can use 1 channel (row freeze disabled) or 2 channels (row freeze enabled).\n// When the contents of a column didn't stray off its limit, we move its channels into the corresponding group\n// based on its position (within frozen rows/columns groups or not).\n// At the end of the operation our 1-4 groups will each have a ImDrawCmd using the same ClipRect.\n// This function assume that each column are pointing to a distinct draw channel,\n// otherwise merge_group->ChannelsCount will not match set bit count of merge_group->ChannelsMask.\n//\n// Column channels will not be merged into one of the 1-4 groups in the following cases:\n// - The contents stray off its clipping rectangle (we only compare the MaxX value, not the MinX value).\n//   Direct ImDrawList calls won't be taken into account by default, if you use them make sure the ImGui:: bounds\n//   matches, by e.g. calling SetCursorScreenPos().\n// - The channel uses more than one draw command itself. We drop all our attempt at merging stuff here..\n//   we could do better but it's going to be rare and probably not worth the hassle.\n// Columns for which the draw channel(s) haven't been merged with other will use their own ImDrawCmd.\n//\n// This function is particularly tricky to understand.. take a breath.\nvoid ImGui::TableMergeDrawChannels(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\tImDrawListSplitter* splitter = table->DrawSplitter;\n\tconst bool has_freeze_v = (table->FreezeRowsCount > 0);\n\tconst bool has_freeze_h = (table->FreezeColumnsCount > 0);\n\tIM_ASSERT(splitter->_Current == 0);\n\n\t// Track which groups we are going to attempt to merge, and which channels goes into each group.\n\tstruct MergeGroup\n\t{\n\t\tImRect          ClipRect;\n\t\tint             ChannelsCount = 0;\n\t\tImBitArrayPtr   ChannelsMask = NULL;\n\t};\n\tint merge_group_mask = 0x00;\n\tMergeGroup merge_groups[4];\n\n\t// Use a reusable temp buffer for the merge masks as they are dynamically sized.\n\tconst int max_draw_channels = (4 + table->ColumnsCount * 2);\n\tconst int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels);\n\tg.TempBuffer.reserve(size_for_masks_bitarrays_one * 5);\n\tmemset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5);\n\tfor (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++)\n\t\tmerge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n));\n\tImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4));\n\n\t// 1. Scan channels and take note of those which can be merged\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tif (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))\n\t\t\tcontinue;\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t\tconst int merge_group_sub_count = has_freeze_v ? 2 : 1;\n\t\tfor (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++)\n\t\t{\n\t\t\tconst int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen;\n\n\t\t\t// Don't attempt to merge if there are multiple draw calls within the column\n\t\t\tImDrawChannel* src_channel = &splitter->_Channels[channel_no];\n\t\t\tif (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()\n\t\t\t\tsrc_channel->_CmdBuffer.pop_back();\n\t\t\tif (src_channel->_CmdBuffer.Size != 1)\n\t\t\t\tcontinue;\n\n\t\t\t// Find out the width of this merge group and check if it will fit in our column\n\t\t\t// (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it)\n\t\t\tif (!(column->Flags & ImGuiTableColumnFlags_NoClip))\n\t\t\t{\n\t\t\t\tfloat content_max_x;\n\t\t\t\tif (!has_freeze_v)\n\t\t\t\t\tcontent_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze\n\t\t\t\telse if (merge_group_sub_n == 0)\n\t\t\t\t\tcontent_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed);   // Row freeze: use width before freeze\n\t\t\t\telse\n\t\t\t\t\tcontent_max_x = column->ContentMaxXUnfrozen;                                        // Row freeze: use width after freeze\n\t\t\t\tif (content_max_x > column->ClipRect.Max.x)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2);\n\t\t\tIM_ASSERT(channel_no < max_draw_channels);\n\t\t\tMergeGroup* merge_group = &merge_groups[merge_group_n];\n\t\t\tif (merge_group->ChannelsCount == 0)\n\t\t\t\tmerge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);\n\t\t\tImBitArraySetBit(merge_group->ChannelsMask, channel_no);\n\t\t\tmerge_group->ChannelsCount++;\n\t\t\tmerge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect);\n\t\t\tmerge_group_mask |= (1 << merge_group_n);\n\t\t}\n\n\t\t// Invalidate current draw channel\n\t\t// (we don't clear DrawChannelFrozen/DrawChannelUnfrozen solely to facilitate debugging/later inspection of data)\n\t\tcolumn->DrawChannelCurrent = (ImGuiTableDrawChannelIdx)-1;\n\t}\n\n\t// [DEBUG] Display merge groups\n#if 0\n\tif (g.IO.KeyShift)\n\t\tfor (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++)\n\t\t{\n\t\t\tMergeGroup* merge_group = &merge_groups[merge_group_n];\n\t\t\tif (merge_group->ChannelsCount == 0)\n\t\t\t\tcontinue;\n\t\t\tchar buf[32];\n\t\t\tImFormatString(buf, 32, \"MG%d:%d\", merge_group_n, merge_group->ChannelsCount);\n\t\t\tImVec2 text_pos = merge_group->ClipRect.Min + ImVec2(4, 4);\n\t\t\tImVec2 text_size = CalcTextSize(buf, NULL);\n\t\t\tGetForegroundDrawList()->AddRectFilled(text_pos, text_pos + text_size, IM_COL32(0, 0, 0, 255));\n\t\t\tGetForegroundDrawList()->AddText(text_pos, IM_COL32(255, 255, 0, 255), buf, NULL);\n\t\t\tGetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 255, 0, 255));\n\t\t}\n#endif\n\n\t// 2. Rewrite channel list in our preferred order\n\tif (merge_group_mask != 0)\n\t{\n\t\t// We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels().\n\t\tconst int LEADING_DRAW_CHANNELS = 2;\n\t\tg.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized\n\t\tImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;\n\t\tImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count);\n\t\tImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen);\n\t\tIM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);\n\t\tint remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS);\n\t\t//ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect;\n\t\tImRect host_rect = table->HostClipRect;\n\t\tfor (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++)\n\t\t{\n\t\t\tif (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount)\n\t\t\t{\n\t\t\t\tMergeGroup* merge_group = &merge_groups[merge_group_n];\n\t\t\t\tImRect merge_clip_rect = merge_group->ClipRect;\n\n\t\t\t\t// Extend outer-most clip limits to match those of host, so draw calls can be merged even if\n\t\t\t\t// outer-most columns have some outer padding offsetting them from their parent ClipRect.\n\t\t\t\t// The principal cases this is dealing with are:\n\t\t\t\t// - On a same-window table (not scrolling = single group), all fitting columns ClipRect -> will extend and match host ClipRect -> will merge\n\t\t\t\t// - Columns can use padding and have left-most ClipRect.Min.x and right-most ClipRect.Max.x != from host ClipRect -> will extend and match host ClipRect -> will merge\n\t\t\t\t// FIXME-TABLE FIXME-WORKRECT: We are wasting a merge opportunity on tables without scrolling if column doesn't fit\n\t\t\t\t// within host clip rect, solely because of the half-padding difference between window->WorkRect and window->InnerClipRect.\n\t\t\t\tif ((merge_group_n & 1) == 0 || !has_freeze_h)\n\t\t\t\t\tmerge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x);\n\t\t\t\tif ((merge_group_n & 2) == 0 || !has_freeze_v)\n\t\t\t\t\tmerge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y);\n\t\t\t\tif ((merge_group_n & 1) != 0)\n\t\t\t\t\tmerge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x);\n\t\t\t\tif ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0)\n\t\t\t\t\tmerge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y);\n\t\t\t\t//GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); // [DEBUG]\n\t\t\t\t//GetForegroundDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200));\n\t\t\t\t//GetForegroundDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200));\n\t\t\t\tremaining_count -= merge_group->ChannelsCount;\n\t\t\t\tfor (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++)\n\t\t\t\t\tremaining_mask[n] &= ~merge_group->ChannelsMask[n];\n\t\t\t\tfor (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)\n\t\t\t\t{\n\t\t\t\t\t// Copy + overwrite new clip rect\n\t\t\t\t\tif (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tIM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n);\n\t\t\t\t\tmerge_channels_count--;\n\n\t\t\t\t\tImDrawChannel* channel = &splitter->_Channels[n];\n\t\t\t\t\tIM_ASSERT(channel->_CmdBuffer.Size == 1 && merge_clip_rect.Contains(ImRect(channel->_CmdBuffer[0].ClipRect)));\n\t\t\t\t\tchannel->_CmdBuffer[0].ClipRect = merge_clip_rect.ToVec4();\n\t\t\t\t\tmemcpy(dst_tmp++, channel, sizeof(ImDrawChannel));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1)\n\t\t\tif (merge_group_n == 1 && has_freeze_v)\n\t\t\t\tmemcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel));\n\t\t}\n\n\t\t// Append unmergeable channels that we didn't reorder at the end of the list\n\t\tfor (int n = 0; n < splitter->_Count && remaining_count != 0; n++)\n\t\t{\n\t\t\tif (!IM_BITARRAY_TESTBIT(remaining_mask, n))\n\t\t\t\tcontinue;\n\t\t\tImDrawChannel* channel = &splitter->_Channels[n];\n\t\t\tmemcpy(dst_tmp++, channel, sizeof(ImDrawChannel));\n\t\t\tremaining_count--;\n\t\t}\n\t\tIM_ASSERT(dst_tmp == g.DrawChannelsTempMergeBuffer.Data + g.DrawChannelsTempMergeBuffer.Size);\n\t\tmemcpy(splitter->_Channels.Data + LEADING_DRAW_CHANNELS, g.DrawChannelsTempMergeBuffer.Data, (splitter->_Count - LEADING_DRAW_CHANNELS) * sizeof(ImDrawChannel));\n\t}\n}\n\n// FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow)\nvoid ImGui::TableDrawBorders(ImGuiTable* table)\n{\n\tImGuiWindow* inner_window = table->InnerWindow;\n\tif (!table->OuterWindow->ClipRect.Overlaps(table->OuterRect))\n\t\treturn;\n\n\tImDrawList* inner_drawlist = inner_window->DrawList;\n\ttable->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0);\n\tinner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);\n\n\t// Draw inner border and resizing feedback\n\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);\n\tconst float border_size = TABLE_BORDER_SIZE;\n\tconst float draw_y1 = table->InnerRect.Min.y;\n\tconst float draw_y2_body = table->InnerRect.Max.y;\n\tconst float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1;\n\tif (table->Flags & ImGuiTableFlags_BordersInnerV)\n\t{\n\t\tfor (int order_n = 0; order_n < table->ColumnsCount; order_n++)\n\t\t{\n\t\t\tif (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))\n\t\t\t\tcontinue;\n\n\t\t\tconst int column_n = table->DisplayOrderToIndex[order_n];\n\t\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\t\tconst bool is_hovered = (table->HoveredColumnBorder == column_n);\n\t\t\tconst bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);\n\t\t\tconst bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;\n\t\t\tconst bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1);\n\t\t\tif (column->MaxX > table->InnerClipRect.Max.x && !is_resized)\n\t\t\t\tcontinue;\n\n\t\t\t// Decide whether right-most column is visible\n\t\t\tif (column->NextEnabledColumn == -1 && !is_resizable)\n\t\t\t\tif ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || (table->Flags & ImGuiTableFlags_NoHostExtendX))\n\t\t\t\t\tcontinue;\n\t\t\tif (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size..\n\t\t\t\tcontinue;\n\n\t\t\t// Draw in outer window so right-most column won't be clipped\n\t\t\t// Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling.\n\t\t\tImU32 col;\n\t\t\tfloat draw_y2;\n\t\t\tif (is_hovered || is_resized || is_frozen_separator)\n\t\t\t{\n\t\t\t\tdraw_y2 = draw_y2_body;\n\t\t\t\tcol = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdraw_y2 = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? draw_y2_head : draw_y2_body;\n\t\t\t\tcol = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? table->BorderColorStrong : table->BorderColorLight;\n\t\t\t}\n\n\t\t\tif (draw_y2 > draw_y1)\n\t\t\t\tinner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), col, border_size);\n\t\t}\n\t}\n\n\t// Draw outer border\n\t// FIXME: could use AddRect or explicit VLine/HLine helper?\n\tif (table->Flags & ImGuiTableFlags_BordersOuter)\n\t{\n\t\t// Display outer border offset by 1 which is a simple way to display it without adding an extra draw call\n\t\t// (Without the offset, in outer_window it would be rendered behind cells, because child windows are above their\n\t\t// parent. In inner_window, it won't reach out over scrollbars. Another weird solution would be to display part\n\t\t// of it in inner window, and the part that's over scrollbars in the outer window..)\n\t\t// Either solution currently won't allow us to use a larger border size: the border would clipped.\n\t\tconst ImRect outer_border = table->OuterRect;\n\t\tconst ImU32 outer_col = table->BorderColorStrong;\n\t\tif ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)\n\t\t{\n\t\t\tinner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size);\n\t\t}\n\t\telse if (table->Flags & ImGuiTableFlags_BordersOuterV)\n\t\t{\n\t\t\tinner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size);\n\t\t\tinner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size);\n\t\t}\n\t\telse if (table->Flags & ImGuiTableFlags_BordersOuterH)\n\t\t{\n\t\t\tinner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size);\n\t\t\tinner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size);\n\t\t}\n\t}\n\tif ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y)\n\t{\n\t\t// Draw bottom-most row border\n\t\tconst float border_y = table->RowPosY2;\n\t\tif (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y)\n\t\t\tinner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size);\n\t}\n\n\tinner_drawlist->PopClipRect();\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Sorting\n//-------------------------------------------------------------------------\n// - TableGetSortSpecs()\n// - TableFixColumnSortDirection() [Internal]\n// - TableGetColumnNextSortDirection() [Internal]\n// - TableSetColumnSortDirection() [Internal]\n// - TableSortSpecsSanitize() [Internal]\n// - TableSortSpecsBuild() [Internal]\n//-------------------------------------------------------------------------\n\n// Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set)\n// When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have\n// changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting,\n// else you may wastefully sort your data every frame!\n// Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()!\nImGuiTableSortSpecs* ImGui::TableGetSortSpecs()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL);\n\n\tif (!(table->Flags & ImGuiTableFlags_Sortable))\n\t\treturn NULL;\n\n\t// Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths.\n\tif (!table->IsLayoutLocked)\n\t\tTableUpdateLayout(table);\n\n\tTableSortSpecsBuild(table);\n\treturn &table->SortSpecs;\n}\n\nstatic inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n)\n{\n\tIM_ASSERT(n < column->SortDirectionsAvailCount);\n\treturn (column->SortDirectionsAvailList >> (n << 1)) & 0x03;\n}\n\n// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending)\nvoid ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column)\n{\n\tif (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0)\n\t\treturn;\n\tcolumn->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0);\n\ttable->IsSortSpecsDirty = true;\n}\n\n// Calculate next sort direction that would be set after clicking the column\n// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click.\n// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op.\nIM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2);\nImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column)\n{\n\tIM_ASSERT(column->SortDirectionsAvailCount > 0);\n\tif (column->SortOrder == -1)\n\t\treturn TableGetColumnAvailSortDirection(column, 0);\n\tfor (int n = 0; n < 3; n++)\n\t\tif (column->SortDirection == TableGetColumnAvailSortDirection(column, n))\n\t\t\treturn TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount);\n\tIM_ASSERT(0);\n\treturn ImGuiSortDirection_None;\n}\n\n// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert\n// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code.\nvoid ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\n\tif (!(table->Flags & ImGuiTableFlags_SortMulti))\n\t\tappend_to_sort_specs = false;\n\tif (!(table->Flags & ImGuiTableFlags_SortTristate))\n\t\tIM_ASSERT(sort_direction != ImGuiSortDirection_None);\n\n\tImGuiTableColumnIdx sort_order_max = 0;\n\tif (append_to_sort_specs)\n\t\tfor (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)\n\t\t\tsort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder);\n\n\tImGuiTableColumn* column = &table->Columns[column_n];\n\tcolumn->SortDirection = (ImU8)sort_direction;\n\tif (column->SortDirection == ImGuiSortDirection_None)\n\t\tcolumn->SortOrder = -1;\n\telse if (column->SortOrder == -1 || !append_to_sort_specs)\n\t\tcolumn->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0;\n\n\tfor (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)\n\t{\n\t\tImGuiTableColumn* other_column = &table->Columns[other_column_n];\n\t\tif (other_column != column && !append_to_sort_specs)\n\t\t\tother_column->SortOrder = -1;\n\t\tTableFixColumnSortDirection(table, other_column);\n\t}\n\ttable->IsSettingsDirty = true;\n\ttable->IsSortSpecsDirty = true;\n}\n\nvoid ImGui::TableSortSpecsSanitize(ImGuiTable* table)\n{\n\tIM_ASSERT(table->Flags & ImGuiTableFlags_Sortable);\n\n\t// Clear SortOrder from hidden column and verify that there's no gap or duplicate.\n\tint sort_order_count = 0;\n\tImU64 sort_order_mask = 0x00;\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (column->SortOrder != -1 && !column->IsEnabled)\n\t\t\tcolumn->SortOrder = -1;\n\t\tif (column->SortOrder == -1)\n\t\t\tcontinue;\n\t\tsort_order_count++;\n\t\tsort_order_mask |= ((ImU64)1 << column->SortOrder);\n\t\tIM_ASSERT(sort_order_count < (int)sizeof(sort_order_mask) * 8);\n\t}\n\n\tconst bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1);\n\tconst bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti);\n\tif (need_fix_linearize || need_fix_single_sort_order)\n\t{\n\t\tImU64 fixed_mask = 0x00;\n\t\tfor (int sort_n = 0; sort_n < sort_order_count; sort_n++)\n\t\t{\n\t\t\t// Fix: Rewrite sort order fields if needed so they have no gap or duplicate.\n\t\t\t// (e.g. SortOrder 0 disappeared, SortOrder 1..2 exists --> rewrite then as SortOrder 0..1)\n\t\t\tint column_with_smallest_sort_order = -1;\n\t\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\t\tif ((fixed_mask & ((ImU64)1 << (ImU64)column_n)) == 0 && table->Columns[column_n].SortOrder != -1)\n\t\t\t\t\tif (column_with_smallest_sort_order == -1 || table->Columns[column_n].SortOrder < table->Columns[column_with_smallest_sort_order].SortOrder)\n\t\t\t\t\t\tcolumn_with_smallest_sort_order = column_n;\n\t\t\tIM_ASSERT(column_with_smallest_sort_order != -1);\n\t\t\tfixed_mask |= ((ImU64)1 << column_with_smallest_sort_order);\n\t\t\ttable->Columns[column_with_smallest_sort_order].SortOrder = (ImGuiTableColumnIdx)sort_n;\n\n\t\t\t// Fix: Make sure only one column has a SortOrder if ImGuiTableFlags_MultiSortable is not set.\n\t\t\tif (need_fix_single_sort_order)\n\t\t\t{\n\t\t\t\tsort_order_count = 1;\n\t\t\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\t\t\tif (column_n != column_with_smallest_sort_order)\n\t\t\t\t\t\ttable->Columns[column_n].SortOrder = -1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fallback default sort order (if no column with the ImGuiTableColumnFlags_DefaultSort flag)\n\tif (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))\n\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t{\n\t\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\t\tif (column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_NoSort))\n\t\t\t{\n\t\t\t\tsort_order_count = 1;\n\t\t\t\tcolumn->SortOrder = 0;\n\t\t\t\tcolumn->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\ttable->SortSpecsCount = (ImGuiTableColumnIdx)sort_order_count;\n}\n\nvoid ImGui::TableSortSpecsBuild(ImGuiTable* table)\n{\n\tbool dirty = table->IsSortSpecsDirty;\n\tif (dirty)\n\t{\n\t\tTableSortSpecsSanitize(table);\n\t\ttable->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);\n\t\ttable->SortSpecs.SpecsDirty = true; // Mark as dirty for user\n\t\ttable->IsSortSpecsDirty = false; // Mark as not dirty for us\n\t}\n\n\t// Write output\n\tImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;\n\tif (dirty && sort_specs != NULL)\n\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t{\n\t\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\t\tif (column->SortOrder == -1)\n\t\t\t\tcontinue;\n\t\t\tIM_ASSERT(column->SortOrder < table->SortSpecsCount);\n\t\t\tImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder];\n\t\t\tsort_spec->ColumnUserID = column->UserID;\n\t\t\tsort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n;\n\t\t\tsort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;\n\t\t\tsort_spec->SortDirection = column->SortDirection;\n\t\t}\n\n\ttable->SortSpecs.Specs = sort_specs;\n\ttable->SortSpecs.SpecsCount = table->SortSpecsCount;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Headers\n//-------------------------------------------------------------------------\n// - TableGetHeaderRowHeight() [Internal]\n// - TableHeadersRow()\n// - TableHeader()\n//-------------------------------------------------------------------------\n\nfloat ImGui::TableGetHeaderRowHeight()\n{\n\t// Caring for a minor edge case:\n\t// Calculate row height, for the unlikely case that some labels may be taller than others.\n\t// If we didn't do that, uneven header height would highlight but smaller one before the tallest wouldn't catch input for all height.\n\t// In your custom header row you may omit this all together and just call TableNextRow() without a height...\n\tfloat row_height = GetTextLineHeight();\n\tint columns_count = TableGetColumnCount();\n\tfor (int column_n = 0; column_n < columns_count; column_n++)\n\t{\n\t\tImGuiTableColumnFlags flags = TableGetColumnFlags(column_n);\n\t\tif ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel))\n\t\t\trow_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y);\n\t}\n\trow_height += GetStyle().CellPadding.y * 2.0f;\n\treturn row_height;\n}\n\n// [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn().\n// The intent is that advanced users willing to create customized headers would not need to use this helper\n// and can create their own! For example: TableHeader() may be preceeded by Checkbox() or other custom widgets.\n// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this.\n// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy.\n// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public.\nvoid ImGui::TableHeadersRow()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && \"Need to call TableHeadersRow() after BeginTable()!\");\n\n\t// Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)\n\tif (!table->IsLayoutLocked)\n\t\tTableUpdateLayout(table);\n\n\t// Open row\n\tconst float row_y1 = GetCursorScreenPos().y;\n\tconst float row_height = TableGetHeaderRowHeight();\n\tTableNextRow(ImGuiTableRowFlags_Headers, row_height);\n\tif (table->HostSkipItems) // Merely an optimization, you may skip in your own code.\n\t\treturn;\n\n\tconst int columns_count = TableGetColumnCount();\n\tfor (int column_n = 0; column_n < columns_count; column_n++)\n\t{\n\t\tif (!TableSetColumnIndex(column_n))\n\t\t\tcontinue;\n\n\t\t// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)\n\t\t// In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.\n\t\tconst char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? \"\" : TableGetColumnName(column_n);\n\t\tPushID(column_n);\n\t\tTableHeader(name);\n\t\tPopID();\n\t}\n\n\t// Allow opening popup from the right-most section after the last column.\n\tImVec2 mouse_pos = ImGui::GetMousePos();\n\tif (IsMouseReleased(1) && TableGetHoveredColumn() == columns_count)\n\t\tif (mouse_pos.y >= row_y1 && mouse_pos.y < row_y1 + row_height)\n\t\t\tTableOpenContextMenu(-1); // Will open a non-column-specific popup.\n}\n\n// Emit a column header (text + optional sort order)\n// We cpu-clip text here so that all columns headers can be merged into a same draw call.\n// Note that because of how we cpu-clip and display sorting indicators, you _cannot_ use SameLine() after a TableHeader()\nvoid ImGui::TableHeader(const char* label)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiTable* table = g.CurrentTable;\n\tIM_ASSERT(table != NULL && \"Need to call TableHeader() after BeginTable()!\");\n\tIM_ASSERT(table->CurrentColumn != -1);\n\tconst int column_n = table->CurrentColumn;\n\tImGuiTableColumn* column = &table->Columns[column_n];\n\n\t// Label\n\tif (label == NULL)\n\t\tlabel = \"\";\n\tconst char* label_end = FindRenderedTextEnd(label);\n\tImVec2 label_size = CalcTextSize(label, label_end, true);\n\tImVec2 label_pos = window->DC.CursorPos;\n\n\t// If we already got a row height, there's use that.\n\t// FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect?\n\tImRect cell_r = TableGetCellBgRect(table, column_n);\n\tfloat label_height = ImMax(label_size.y, table->RowMinHeight - table->RowCellPaddingY * 2.0f);\n\n\t// Calculate ideal size for sort order arrow\n\tfloat w_arrow = 0.0f;\n\tfloat w_sort_text = 0.0f;\n\tchar sort_order_suf[4] = \"\";\n\tconst float ARROW_SCALE = 0.65f;\n\tif ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort))\n\t{\n\t\tw_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x);\n\t\tif (column->SortOrder > 0)\n\t\t{\n\t\t\tImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), \"%d\", column->SortOrder + 1);\n\t\t\tw_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x;\n\t\t}\n\t}\n\n\t// We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging.\n\tfloat max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow;\n\tcolumn->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX);\n\tcolumn->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x);\n\n\t// Keep header highlighted when context menu is open.\n\tconst bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent);\n\tImGuiID id = window->GetID(label);\n\tImRect bb(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0f));\n\tItemSize(ImVec2(0.0f, label_height)); // Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal\n\tif (!ItemAdd(bb, id))\n\t\treturn;\n\n\t//GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG]\n\t//GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG]\n\n\t// Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items.\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap);\n\tif (held || hovered || selected)\n\t{\n\t\tconst ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);\n\t\t//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);\n\t\tTableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn);\n\t}\n\telse\n\t{\n\t\t// Submit single cell bg color in the case we didn't submit a full header row\n\t\tif ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)\n\t\t\tTableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);\n\t}\n\tRenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);\n\tif (held)\n\t\ttable->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;\n\twindow->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;\n\n\t// Drag and drop to re-order columns.\n\t// FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone.\n\tif (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive)\n\t{\n\t\t// While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x\n\t\ttable->ReorderColumn = (ImGuiTableColumnIdx)column_n;\n\t\ttable->InstanceInteracted = table->InstanceCurrent;\n\n\t\t// We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder.\n\t\tif (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x)\n\t\t\tif (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL)\n\t\t\t\tif (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder))\n\t\t\t\t\tif ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))\n\t\t\t\t\t\ttable->ReorderColumnDir = -1;\n\t\tif (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x)\n\t\t\tif (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL)\n\t\t\t\tif (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder))\n\t\t\t\t\tif ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))\n\t\t\t\t\t\ttable->ReorderColumnDir = +1;\n\t}\n\n\t// Sort order arrow\n\tconst float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x);\n\tif ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort))\n\t{\n\t\tif (column->SortOrder != -1)\n\t\t{\n\t\t\tfloat x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text);\n\t\t\tfloat y = label_pos.y;\n\t\t\tif (column->SortOrder > 0)\n\t\t\t{\n\t\t\t\tPushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text, 0.70f));\n\t\t\t\tRenderText(ImVec2(x + g.Style.ItemInnerSpacing.x, y), sort_order_suf);\n\t\t\t\tPopStyleColor();\n\t\t\t\tx += w_sort_text;\n\t\t\t}\n\t\t\tRenderArrow(window->DrawList, ImVec2(x, y), GetColorU32(ImGuiCol_Text), column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE);\n\t\t}\n\n\t\t// Handle clicking on column header to adjust Sort Order\n\t\tif (pressed && table->ReorderColumn != column_n)\n\t\t{\n\t\t\tImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column);\n\t\t\tTableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift);\n\t\t}\n\t}\n\n\t// Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will\n\t// be merged into a single draw call.\n\t//window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE);\n\tRenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size);\n\n\tconst bool text_clipped = label_size.x > (ellipsis_max - label_pos.x);\n\tif (text_clipped && hovered && g.ActiveId == 0)\n\t\tSetItemTooltip(\"%.*s\", (int)(label_end - label), label);\n\n\t// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden\n\tif (IsMouseReleased(1) && IsItemHovered())\n\t\tTableOpenContextMenu(column_n);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Context Menu\n//-------------------------------------------------------------------------\n// - TableOpenContextMenu() [Internal]\n// - TableDrawContextMenu() [Internal]\n//-------------------------------------------------------------------------\n\n// Use -1 to open menu not specific to a given column.\nvoid ImGui::TableOpenContextMenu(int column_n)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTable* table = g.CurrentTable;\n\tif (column_n == -1 && table->CurrentColumn != -1)   // When called within a column automatically use this one (for consistency)\n\t\tcolumn_n = table->CurrentColumn;\n\tif (column_n == table->ColumnsCount)                // To facilitate using with TableGetHoveredColumn()\n\t\tcolumn_n = -1;\n\tIM_ASSERT(column_n >= -1 && column_n < table->ColumnsCount);\n\tif (table->Flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))\n\t{\n\t\ttable->IsContextPopupOpen = true;\n\t\ttable->ContextPopupColumn = (ImGuiTableColumnIdx)column_n;\n\t\ttable->InstanceInteracted = table->InstanceCurrent;\n\t\tconst ImGuiID context_menu_id = ImHashStr(\"##ContextMenu\", 0, table->ID);\n\t\tOpenPopupEx(context_menu_id, ImGuiPopupFlags_None);\n\t}\n}\n\nbool ImGui::TableBeginContextMenuPopup(ImGuiTable* table)\n{\n\tif (!table->IsContextPopupOpen || table->InstanceCurrent != table->InstanceInteracted)\n\t\treturn false;\n\tconst ImGuiID context_menu_id = ImHashStr(\"##ContextMenu\", 0, table->ID);\n\tif (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings))\n\t\treturn true;\n\ttable->IsContextPopupOpen = false;\n\treturn false;\n}\n\n// Output context menu into current window (generally a popup)\n// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data?\nvoid ImGui::TableDrawContextMenu(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\tbool want_separator = false;\n\tconst int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1;\n\tImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL;\n\n\t// Sizing\n\tif (table->Flags & ImGuiTableFlags_Resizable)\n\t{\n\t\tif (column != NULL)\n\t\t{\n\t\t\tconst bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled;\n\t\t\tif (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // \"###SizeOne\"\n\t\t\t\tTableSetColumnWidthAutoSingle(table, column_n);\n\t\t}\n\n\t\tconst char* size_all_desc;\n\t\tif (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame)\n\t\t\tsize_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllFit);        // \"###SizeAll\" All fixed\n\t\telse\n\t\t\tsize_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllDefault);    // \"###SizeAll\" All stretch or mixed\n\t\tif (MenuItem(size_all_desc, NULL))\n\t\t\tTableSetColumnWidthAutoAll(table);\n\t\twant_separator = true;\n\t}\n\n\t// Ordering\n\tif (table->Flags & ImGuiTableFlags_Reorderable)\n\t{\n\t\tif (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder))\n\t\t\ttable->IsResetDisplayOrderRequest = true;\n\t\twant_separator = true;\n\t}\n\n\t// Reset all (should work but seems unnecessary/noisy to expose?)\n\t//if (MenuItem(\"Reset all\"))\n\t//    table->IsResetAllRequest = true;\n\n\t// Sorting\n\t// (modify TableOpenContextMenu() to add _Sortable flag if enabling this)\n#if 0\n\tif ((table->Flags & ImGuiTableFlags_Sortable) && column != NULL && (column->Flags & ImGuiTableColumnFlags_NoSort) == 0)\n\t{\n\t\tif (want_separator)\n\t\t\tSeparator();\n\t\twant_separator = true;\n\n\t\tbool append_to_sort_specs = g.IO.KeyShift;\n\t\tif (MenuItem(\"Sort in Ascending Order\", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Ascending, (column->Flags & ImGuiTableColumnFlags_NoSortAscending) == 0))\n\t\t\tTableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Ascending, append_to_sort_specs);\n\t\tif (MenuItem(\"Sort in Descending Order\", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Descending, (column->Flags & ImGuiTableColumnFlags_NoSortDescending) == 0))\n\t\t\tTableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Descending, append_to_sort_specs);\n\t}\n#endif\n\n\t// Hiding / Visibility\n\tif (table->Flags & ImGuiTableFlags_Hideable)\n\t{\n\t\tif (want_separator)\n\t\t\tSeparator();\n\t\twant_separator = true;\n\n\t\tPushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);\n\t\tfor (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)\n\t\t{\n\t\t\tImGuiTableColumn* other_column = &table->Columns[other_column_n];\n\t\t\tif (other_column->Flags & ImGuiTableColumnFlags_Disabled)\n\t\t\t\tcontinue;\n\n\t\t\tconst char* name = TableGetColumnName(table, other_column_n);\n\t\t\tif (name == NULL || name[0] == 0)\n\t\t\t\tname = \"<Unknown>\";\n\n\t\t\t// Make sure we can't hide the last active column\n\t\t\tbool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;\n\t\t\tif (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1)\n\t\t\t\tmenu_item_active = false;\n\t\t\tif (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active))\n\t\t\t\tother_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled;\n\t\t}\n\t\tPopItemFlag();\n\t}\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Settings (.ini data)\n//-------------------------------------------------------------------------\n// FIXME: The binding/finding/creating flow are too confusing.\n//-------------------------------------------------------------------------\n// - TableSettingsInit() [Internal]\n// - TableSettingsCalcChunkSize() [Internal]\n// - TableSettingsCreate() [Internal]\n// - TableSettingsFindByID() [Internal]\n// - TableGetBoundSettings() [Internal]\n// - TableResetSettings()\n// - TableSaveSettings() [Internal]\n// - TableLoadSettings() [Internal]\n// - TableSettingsHandler_ClearAll() [Internal]\n// - TableSettingsHandler_ApplyAll() [Internal]\n// - TableSettingsHandler_ReadOpen() [Internal]\n// - TableSettingsHandler_ReadLine() [Internal]\n// - TableSettingsHandler_WriteAll() [Internal]\n// - TableSettingsInstallHandler() [Internal]\n//-------------------------------------------------------------------------\n// [Init] 1: TableSettingsHandler_ReadXXXX()   Load and parse .ini file into TableSettings.\n// [Main] 2: TableLoadSettings()               When table is created, bind Table to TableSettings, serialize TableSettings data into Table.\n// [Main] 3: TableSaveSettings()               When table properties are modified, serialize Table data into bound or new TableSettings, mark .ini as dirty.\n// [Main] 4: TableSettingsHandler_WriteAll()   When .ini file is dirty (which can come from other source), save TableSettings into .ini file.\n//-------------------------------------------------------------------------\n\n// Clear and initialize empty settings instance\nstatic void TableSettingsInit(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max)\n{\n\tIM_PLACEMENT_NEW(settings) ImGuiTableSettings();\n\tImGuiTableColumnSettings* settings_column = settings->GetColumnSettings();\n\tfor (int n = 0; n < columns_count_max; n++, settings_column++)\n\t\tIM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings();\n\tsettings->ID = id;\n\tsettings->ColumnsCount = (ImGuiTableColumnIdx)columns_count;\n\tsettings->ColumnsCountMax = (ImGuiTableColumnIdx)columns_count_max;\n\tsettings->WantApply = true;\n}\n\nstatic size_t TableSettingsCalcChunkSize(int columns_count)\n{\n\treturn sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings);\n}\n\nImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count));\n\tTableSettingsInit(settings, id, columns_count, columns_count);\n\treturn settings;\n}\n\n// Find existing settings\nImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id)\n{\n\t// FIXME-OPT: Might want to store a lookup map for this?\n\tImGuiContext& g = *GImGui;\n\tfor (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))\n\t\tif (settings->ID == id)\n\t\t\treturn settings;\n\treturn NULL;\n}\n\n// Get settings for a given table, NULL if none\nImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table)\n{\n\tif (table->SettingsOffset != -1)\n\t{\n\t\tImGuiContext& g = *GImGui;\n\t\tImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);\n\t\tIM_ASSERT(settings->ID == table->ID);\n\t\tif (settings->ColumnsCountMax >= table->ColumnsCount)\n\t\t\treturn settings; // OK\n\t\tsettings->ID = 0; // Invalidate storage, we won't fit because of a count change\n\t}\n\treturn NULL;\n}\n\n// Restore initial state of table (with or without saved settings)\nvoid ImGui::TableResetSettings(ImGuiTable* table)\n{\n\ttable->IsInitializing = table->IsSettingsDirty = true;\n\ttable->IsResetAllRequest = false;\n\ttable->IsSettingsRequestLoad = false;                   // Don't reload from ini\n\ttable->SettingsLoadedFlags = ImGuiTableFlags_None;      // Mark as nothing loaded so our initialized data becomes authoritative\n}\n\nvoid ImGui::TableSaveSettings(ImGuiTable* table)\n{\n\ttable->IsSettingsDirty = false;\n\tif (table->Flags & ImGuiTableFlags_NoSavedSettings)\n\t\treturn;\n\n\t// Bind or create settings data\n\tImGuiContext& g = *GImGui;\n\tImGuiTableSettings* settings = TableGetBoundSettings(table);\n\tif (settings == NULL)\n\t{\n\t\tsettings = TableSettingsCreate(table->ID, table->ColumnsCount);\n\t\ttable->SettingsOffset = g.SettingsTables.offset_from_ptr(settings);\n\t}\n\tsettings->ColumnsCount = (ImGuiTableColumnIdx)table->ColumnsCount;\n\n\t// Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings\n\tIM_ASSERT(settings->ID == table->ID);\n\tIM_ASSERT(settings->ColumnsCount == table->ColumnsCount && settings->ColumnsCountMax >= settings->ColumnsCount);\n\tImGuiTableColumn* column = table->Columns.Data;\n\tImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();\n\n\tbool save_ref_scale = false;\n\tsettings->SaveFlags = ImGuiTableFlags_None;\n\tfor (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++)\n\t{\n\t\tconst float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest;\n\t\tcolumn_settings->WidthOrWeight = width_or_weight;\n\t\tcolumn_settings->Index = (ImGuiTableColumnIdx)n;\n\t\tcolumn_settings->DisplayOrder = column->DisplayOrder;\n\t\tcolumn_settings->SortOrder = column->SortOrder;\n\t\tcolumn_settings->SortDirection = column->SortDirection;\n\t\tcolumn_settings->IsEnabled = column->IsUserEnabled;\n\t\tcolumn_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0;\n\t\tif ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0)\n\t\t\tsave_ref_scale = true;\n\n\t\t// We skip saving some data in the .ini file when they are unnecessary to restore our state.\n\t\t// Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f.\n\t\t// FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present.\n\t\tif (width_or_weight != column->InitStretchWeightOrWidth)\n\t\t\tsettings->SaveFlags |= ImGuiTableFlags_Resizable;\n\t\tif (column->DisplayOrder != n)\n\t\t\tsettings->SaveFlags |= ImGuiTableFlags_Reorderable;\n\t\tif (column->SortOrder != -1)\n\t\t\tsettings->SaveFlags |= ImGuiTableFlags_Sortable;\n\t\tif (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))\n\t\t\tsettings->SaveFlags |= ImGuiTableFlags_Hideable;\n\t}\n\tsettings->SaveFlags &= table->Flags;\n\tsettings->RefScale = save_ref_scale ? table->RefScale : 0.0f;\n\n\tMarkIniSettingsDirty();\n}\n\nvoid ImGui::TableLoadSettings(ImGuiTable* table)\n{\n\tImGuiContext& g = *GImGui;\n\ttable->IsSettingsRequestLoad = false;\n\tif (table->Flags & ImGuiTableFlags_NoSavedSettings)\n\t\treturn;\n\n\t// Bind settings\n\tImGuiTableSettings* settings;\n\tif (table->SettingsOffset == -1)\n\t{\n\t\tsettings = TableSettingsFindByID(table->ID);\n\t\tif (settings == NULL)\n\t\t\treturn;\n\t\tif (settings->ColumnsCount != table->ColumnsCount) // Allow settings if columns count changed. We could otherwise decide to return...\n\t\t\ttable->IsSettingsDirty = true;\n\t\ttable->SettingsOffset = g.SettingsTables.offset_from_ptr(settings);\n\t}\n\telse\n\t{\n\t\tsettings = TableGetBoundSettings(table);\n\t}\n\n\ttable->SettingsLoadedFlags = settings->SaveFlags;\n\ttable->RefScale = settings->RefScale;\n\n\t// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn\n\tImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();\n\tImU64 display_order_mask = 0;\n\tfor (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++)\n\t{\n\t\tint column_n = column_settings->Index;\n\t\tif (column_n < 0 || column_n >= table->ColumnsCount)\n\t\t\tcontinue;\n\n\t\tImGuiTableColumn* column = &table->Columns[column_n];\n\t\tif (settings->SaveFlags & ImGuiTableFlags_Resizable)\n\t\t{\n\t\t\tif (column_settings->IsStretch)\n\t\t\t\tcolumn->StretchWeight = column_settings->WidthOrWeight;\n\t\t\telse\n\t\t\t\tcolumn->WidthRequest = column_settings->WidthOrWeight;\n\t\t\tcolumn->AutoFitQueue = 0x00;\n\t\t}\n\t\tif (settings->SaveFlags & ImGuiTableFlags_Reorderable)\n\t\t\tcolumn->DisplayOrder = column_settings->DisplayOrder;\n\t\telse\n\t\t\tcolumn->DisplayOrder = (ImGuiTableColumnIdx)column_n;\n\t\tdisplay_order_mask |= (ImU64)1 << column->DisplayOrder;\n\t\tcolumn->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;\n\t\tcolumn->SortOrder = column_settings->SortOrder;\n\t\tcolumn->SortDirection = column_settings->SortDirection;\n\t}\n\n\t// Validate and fix invalid display order data\n\tconst ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1;\n\tif (display_order_mask != expected_display_order_mask)\n\t\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\t\ttable->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n;\n\n\t// Rebuild index\n\tfor (int column_n = 0; column_n < table->ColumnsCount; column_n++)\n\t\ttable->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n;\n}\n\nstatic void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)\n{\n\tImGuiContext& g = *ctx;\n\tfor (int i = 0; i != g.Tables.GetMapSize(); i++)\n\t\tif (ImGuiTable* table = g.Tables.TryGetMapData(i))\n\t\t\ttable->SettingsOffset = -1;\n\tg.SettingsTables.clear();\n}\n\n// Apply to existing windows (if any)\nstatic void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)\n{\n\tImGuiContext& g = *ctx;\n\tfor (int i = 0; i != g.Tables.GetMapSize(); i++)\n\t\tif (ImGuiTable* table = g.Tables.TryGetMapData(i))\n\t\t{\n\t\t\ttable->IsSettingsRequestLoad = true;\n\t\t\ttable->SettingsOffset = -1;\n\t\t}\n}\n\nstatic void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)\n{\n\tImGuiID id = 0;\n\tint columns_count = 0;\n\tif (sscanf(name, \"0x%08X,%d\", &id, &columns_count) < 2)\n\t\treturn NULL;\n\n\tif (ImGuiTableSettings* settings = ImGui::TableSettingsFindByID(id))\n\t{\n\t\tif (settings->ColumnsCountMax >= columns_count)\n\t\t{\n\t\t\tTableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle\n\t\t\treturn settings;\n\t\t}\n\t\tsettings->ID = 0; // Invalidate storage, we won't fit because of a count change\n\t}\n\treturn ImGui::TableSettingsCreate(id, columns_count);\n}\n\nstatic void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)\n{\n\t// \"Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v\"\n\tImGuiTableSettings* settings = (ImGuiTableSettings*)entry;\n\tfloat f = 0.0f;\n\tint column_n = 0, r = 0, n = 0;\n\n\tif (sscanf(line, \"RefScale=%f\", &f) == 1) { settings->RefScale = f; return; }\n\n\tif (sscanf(line, \"Column %d%n\", &column_n, &r) == 1)\n\t{\n\t\tif (column_n < 0 || column_n >= settings->ColumnsCount)\n\t\t\treturn;\n\t\tline = ImStrSkipBlank(line + r);\n\t\tchar c = 0;\n\t\tImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n;\n\t\tcolumn->Index = (ImGuiTableColumnIdx)column_n;\n\t\tif (sscanf(line, \"UserID=0x%08X%n\", (ImU32*)&n, &r) == 1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; }\n\t\tif (sscanf(line, \"Width=%d%n\", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; }\n\t\tif (sscanf(line, \"Weight=%f%n\", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; }\n\t\tif (sscanf(line, \"Visible=%d%n\", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; }\n\t\tif (sscanf(line, \"Order=%d%n\", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; }\n\t\tif (sscanf(line, \"Sort=%d%c%n\", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; }\n\t}\n}\n\nstatic void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)\n{\n\tImGuiContext& g = *ctx;\n\tfor (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))\n\t{\n\t\tif (settings->ID == 0) // Skip ditched settings\n\t\t\tcontinue;\n\n\t\t// TableSaveSettings() may clear some of those flags when we establish that the data can be stripped\n\t\t// (e.g. Order was unchanged)\n\t\tconst bool save_size = (settings->SaveFlags & ImGuiTableFlags_Resizable) != 0;\n\t\tconst bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0;\n\t\tconst bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0;\n\t\tconst bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0;\n\t\tif (!save_size && !save_visible && !save_order && !save_sort)\n\t\t\tcontinue;\n\n\t\tbuf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve\n\t\tbuf->appendf(\"[%s][0x%08X,%d]\\n\", handler->TypeName, settings->ID, settings->ColumnsCount);\n\t\tif (settings->RefScale != 0.0f)\n\t\t\tbuf->appendf(\"RefScale=%g\\n\", settings->RefScale);\n\t\tImGuiTableColumnSettings* column = settings->GetColumnSettings();\n\t\tfor (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)\n\t\t{\n\t\t\t// \"Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v\"\n\t\t\tbool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1);\n\t\t\tif (!save_column)\n\t\t\t\tcontinue;\n\t\t\tbuf->appendf(\"Column %-2d\", column_n);\n\t\t\tif (column->UserID != 0) { buf->appendf(\" UserID=%08X\", column->UserID); }\n\t\t\tif (save_size && column->IsStretch) { buf->appendf(\" Weight=%.4f\", column->WidthOrWeight); }\n\t\t\tif (save_size && !column->IsStretch) { buf->appendf(\" Width=%d\", (int)column->WidthOrWeight); }\n\t\t\tif (save_visible) { buf->appendf(\" Visible=%d\", column->IsEnabled); }\n\t\t\tif (save_order) { buf->appendf(\" Order=%d\", column->DisplayOrder); }\n\t\t\tif (save_sort && column->SortOrder != -1) { buf->appendf(\" Sort=%d%c\", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); }\n\t\t\tbuf->append(\"\\n\");\n\t\t}\n\t\tbuf->append(\"\\n\");\n\t}\n}\n\nvoid ImGui::TableSettingsAddSettingsHandler()\n{\n\tImGuiSettingsHandler ini_handler;\n\tini_handler.TypeName = \"Table\";\n\tini_handler.TypeHash = ImHashStr(\"Table\");\n\tini_handler.ClearAllFn = TableSettingsHandler_ClearAll;\n\tini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;\n\tini_handler.ReadLineFn = TableSettingsHandler_ReadLine;\n\tini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll;\n\tini_handler.WriteAllFn = TableSettingsHandler_WriteAll;\n\tAddSettingsHandler(&ini_handler);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Garbage Collection\n//-------------------------------------------------------------------------\n// - TableRemove() [Internal]\n// - TableGcCompactTransientBuffers() [Internal]\n// - TableGcCompactSettings() [Internal]\n//-------------------------------------------------------------------------\n\n// Remove Table (currently only used by TestEngine)\nvoid ImGui::TableRemove(ImGuiTable* table)\n{\n\t//IMGUI_DEBUG_PRINT(\"TableRemove() id=0x%08X\\n\", table->ID);\n\tImGuiContext& g = *GImGui;\n\tint table_idx = g.Tables.GetIndex(table);\n\t//memset(table->RawData.Data, 0, table->RawData.size_in_bytes());\n\t//memset(table, 0, sizeof(ImGuiTable));\n\tg.Tables.Remove(table->ID, table);\n\tg.TablesLastTimeActive[table_idx] = -1.0f;\n}\n\n// Free up/compact internal Table buffers for when it gets unused\nvoid ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)\n{\n\t//IMGUI_DEBUG_PRINT(\"TableGcCompactTransientBuffers() id=0x%08X\\n\", table->ID);\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(table->MemoryCompacted == false);\n\ttable->SortSpecs.Specs = NULL;\n\ttable->SortSpecsMulti.clear();\n\ttable->IsSortSpecsDirty = true; // FIXME: In theory shouldn't have to leak into user performing a sort on resume.\n\ttable->ColumnsNames.clear();\n\ttable->MemoryCompacted = true;\n\tfor (int n = 0; n < table->ColumnsCount; n++)\n\t\ttable->Columns[n].NameOffset = -1;\n\tg.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f;\n}\n\nvoid ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data)\n{\n\ttemp_data->DrawSplitter.ClearFreeMemory();\n\ttemp_data->LastTimeActive = -1.0f;\n}\n\n// Compact and remove unused settings data (currently only used by TestEngine)\nvoid ImGui::TableGcCompactSettings()\n{\n\tImGuiContext& g = *GImGui;\n\tint required_memory = 0;\n\tfor (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))\n\t\tif (settings->ID != 0)\n\t\t\trequired_memory += (int)TableSettingsCalcChunkSize(settings->ColumnsCount);\n\tif (required_memory == g.SettingsTables.Buf.Size)\n\t\treturn;\n\tImChunkStream<ImGuiTableSettings> new_chunk_stream;\n\tnew_chunk_stream.Buf.reserve(required_memory);\n\tfor (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))\n\t\tif (settings->ID != 0)\n\t\t\tmemcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount));\n\tg.SettingsTables.swap(new_chunk_stream);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Tables: Debugging\n//-------------------------------------------------------------------------\n// - DebugNodeTable() [Internal]\n//-------------------------------------------------------------------------\n\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\nstatic const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy)\n{\n\tsizing_policy &= ImGuiTableFlags_SizingMask_;\n\tif (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return \"FixedFit\"; }\n\tif (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return \"FixedSame\"; }\n\tif (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return \"StretchProp\"; }\n\tif (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return \"StretchSame\"; }\n\treturn \"N/A\";\n}\n\nvoid ImGui::DebugNodeTable(ImGuiTable* table)\n{\n\tconst bool is_active = (table->LastFrameActive >= GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here.\n\tif (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }\n\tbool open = TreeNode(table, \"Table 0x%08X (%d columns, in '%s')%s\", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? \"\" : \" *Inactive*\");\n\tif (!is_active) { PopStyleColor(); }\n\tif (IsItemHovered())\n\t\tGetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));\n\tif (IsItemVisible() && table->HoveredColumnBody != -1)\n\t\tGetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));\n\tif (!open)\n\t\treturn;\n\tif (table->InstanceCurrent > 0)\n\t\tText(\"** %d instances of same table! Some data below will refer to last instance.\", table->InstanceCurrent + 1);\n\tbool clear_settings = SmallButton(\"Clear settings\");\n\tBulletText(\"OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'\", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));\n\tBulletText(\"ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s\", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? \" (auto)\" : \"\");\n\tBulletText(\"CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f\", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX);\n\tBulletText(\"HoveredColumnBody: %d, HoveredColumnBorder: %d\", table->HoveredColumnBody, table->HoveredColumnBorder);\n\tBulletText(\"ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d\", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn);\n\tfor (int n = 0; n < table->InstanceCurrent + 1; n++)\n\t{\n\t\tImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n);\n\t\tBulletText(\"Instance %d: HoveredRow: %d, LastOuterHeight: %.2f\", n, table_instance->HoveredRowLast, table_instance->LastOuterHeight);\n\t}\n\t//BulletText(\"BgDrawChannels: %d/%d\", 0, table->BgDrawChannelUnfrozen);\n\tfloat sum_weights = 0.0f;\n\tfor (int n = 0; n < table->ColumnsCount; n++)\n\t\tif (table->Columns[n].Flags & ImGuiTableColumnFlags_WidthStretch)\n\t\t\tsum_weights += table->Columns[n].StretchWeight;\n\tfor (int n = 0; n < table->ColumnsCount; n++)\n\t{\n\t\tImGuiTableColumn* column = &table->Columns[n];\n\t\tconst char* name = TableGetColumnName(table, n);\n\t\tchar buf[512];\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf),\n\t\t\t\"Column %d order %d '%s': offset %+.2f to %+.2f%s\\n\"\n\t\t\t\"Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\\n\"\n\t\t\t\"WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\\n\"\n\t\t\t\"MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\\n\"\n\t\t\t\"ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\\n\"\n\t\t\t\"Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..\",\n\t\t\tn, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? \" (Frozen)\" : \"\",\n\t\t\tcolumn->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen,\n\t\t\tcolumn->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f,\n\t\t\tcolumn->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x,\n\t\t\tcolumn->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX,\n\t\t\tcolumn->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? \" (Asc)\" : (column->SortDirection == ImGuiSortDirection_Descending) ? \" (Des)\" : \"\", column->UserID, column->Flags,\n\t\t\t(column->Flags & ImGuiTableColumnFlags_WidthStretch) ? \"WidthStretch \" : \"\",\n\t\t\t(column->Flags & ImGuiTableColumnFlags_WidthFixed) ? \"WidthFixed \" : \"\",\n\t\t\t(column->Flags & ImGuiTableColumnFlags_NoResize) ? \"NoResize \" : \"\");\n\t\tBullet();\n\t\tSelectable(buf);\n\t\tif (IsItemHovered())\n\t\t{\n\t\t\tImRect r(column->MinX, table->OuterRect.Min.y, column->MaxX, table->OuterRect.Max.y);\n\t\t\tGetForegroundDrawList()->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255));\n\t\t}\n\t}\n\tif (ImGuiTableSettings* settings = TableGetBoundSettings(table))\n\t\tDebugNodeTableSettings(settings);\n\tif (clear_settings)\n\t\ttable->IsResetAllRequest = true;\n\tTreePop();\n}\n\nvoid ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings)\n{\n\tif (!TreeNode((void*)(intptr_t)settings->ID, \"Settings 0x%08X (%d columns)\", settings->ID, settings->ColumnsCount))\n\t\treturn;\n\tBulletText(\"SaveFlags: 0x%08X\", settings->SaveFlags);\n\tBulletText(\"ColumnsCount: %d (max %d)\", settings->ColumnsCount, settings->ColumnsCountMax);\n\tfor (int n = 0; n < settings->ColumnsCount; n++)\n\t{\n\t\tImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n];\n\t\tImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None;\n\t\tBulletText(\"Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X\",\n\t\t\tn, column_settings->DisplayOrder, column_settings->SortOrder,\n\t\t\t(sort_dir == ImGuiSortDirection_Ascending) ? \"Asc\" : (sort_dir == ImGuiSortDirection_Descending) ? \"Des\" : \"---\",\n\t\t\tcolumn_settings->IsEnabled, column_settings->IsStretch ? \"Weight\" : \"Width \", column_settings->WidthOrWeight, column_settings->UserID);\n\t}\n\tTreePop();\n}\n\n#else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\nvoid ImGui::DebugNodeTable(ImGuiTable*) {}\nvoid ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}\n\n#endif\n\n//-------------------------------------------------------------------------\n// [SECTION] Columns, BeginColumns, EndColumns, etc.\n// (This is a legacy API, prefer using BeginTable/EndTable!)\n//-------------------------------------------------------------------------\n// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.)\n//-------------------------------------------------------------------------\n// - SetWindowClipRectBeforeSetChannel() [Internal]\n// - GetColumnIndex()\n// - GetColumnsCount()\n// - GetColumnOffset()\n// - GetColumnWidth()\n// - SetColumnOffset()\n// - SetColumnWidth()\n// - PushColumnClipRect() [Internal]\n// - PushColumnsBackground() [Internal]\n// - PopColumnsBackground() [Internal]\n// - FindOrCreateColumns() [Internal]\n// - GetColumnsID() [Internal]\n// - BeginColumns()\n// - NextColumn()\n// - EndColumns()\n// - Columns()\n//-------------------------------------------------------------------------\n\n// [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences,\n// they would meddle many times with the underlying ImDrawCmd.\n// Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let\n// the subsequent single call to SetCurrentChannel() does it things once.\nvoid ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect)\n{\n\tImVec4 clip_rect_vec4 = clip_rect.ToVec4();\n\twindow->ClipRect = clip_rect;\n\twindow->DrawList->_CmdHeader.ClipRect = clip_rect_vec4;\n\twindow->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4;\n}\n\nint ImGui::GetColumnIndex()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;\n}\n\nint ImGui::GetColumnsCount()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\treturn window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;\n}\n\nfloat ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm)\n{\n\treturn offset_norm * (columns->OffMaxX - columns->OffMinX);\n}\n\nfloat ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset)\n{\n\treturn offset / (columns->OffMaxX - columns->OffMinX);\n}\n\nstatic const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;\n\nstatic float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index)\n{\n\t// Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing\n\t// window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(column_index > 0); // We are not supposed to drag column 0.\n\tIM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));\n\n\tfloat x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;\n\tx = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);\n\tif ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths))\n\t\tx = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);\n\n\treturn x;\n}\n\nfloat ImGui::GetColumnOffset(int column_index)\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (columns == NULL)\n\t\treturn 0.0f;\n\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\tIM_ASSERT(column_index < columns->Columns.Size);\n\n\tconst float t = columns->Columns[column_index].OffsetNorm;\n\tconst float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);\n\treturn x_offset;\n}\n\nstatic float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false)\n{\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\n\tfloat offset_norm;\n\tif (before_resize)\n\t\toffset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;\n\telse\n\t\toffset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;\n\treturn ImGui::GetColumnOffsetFromNorm(columns, offset_norm);\n}\n\nfloat ImGui::GetColumnWidth(int column_index)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (columns == NULL)\n\t\treturn GetContentRegionAvail().x;\n\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\treturn GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);\n}\n\nvoid ImGui::SetColumnOffset(int column_index, float offset)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tIM_ASSERT(columns != NULL);\n\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\tIM_ASSERT(column_index < columns->Columns.Size);\n\n\tconst bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1);\n\tconst float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;\n\n\tif (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow))\n\t\toffset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));\n\tcolumns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX);\n\n\tif (preserve_width)\n\t\tSetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));\n}\n\nvoid ImGui::SetColumnWidth(int column_index, float width)\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tIM_ASSERT(columns != NULL);\n\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\tSetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);\n}\n\nvoid ImGui::PushColumnClipRect(int column_index)\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (column_index < 0)\n\t\tcolumn_index = columns->Current;\n\n\tImGuiOldColumnData* column = &columns->Columns[column_index];\n\tPushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);\n}\n\n// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)\nvoid ImGui::PushColumnsBackground()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (columns->Count == 1)\n\t\treturn;\n\n\t// Optimization: avoid SetCurrentChannel() + PushClipRect()\n\tcolumns->HostBackupClipRect = window->ClipRect;\n\tSetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect);\n\tcolumns->Splitter.SetCurrentChannel(window->DrawList, 0);\n}\n\nvoid ImGui::PopColumnsBackground()\n{\n\tImGuiWindow* window = GetCurrentWindowRead();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (columns->Count == 1)\n\t\treturn;\n\n\t// Optimization: avoid PopClipRect() + SetCurrentChannel()\n\tSetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect);\n\tcolumns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1);\n}\n\nImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)\n{\n\t// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.\n\tfor (int n = 0; n < window->ColumnsStorage.Size; n++)\n\t\tif (window->ColumnsStorage[n].ID == id)\n\t\t\treturn &window->ColumnsStorage[n];\n\n\twindow->ColumnsStorage.push_back(ImGuiOldColumns());\n\tImGuiOldColumns* columns = &window->ColumnsStorage.back();\n\tcolumns->ID = id;\n\treturn columns;\n}\n\nImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\n\t// Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.\n\t// In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.\n\tPushID(0x11223347 + (str_id ? 0 : columns_count));\n\tImGuiID id = window->GetID(str_id ? str_id : \"columns\");\n\tPopID();\n\n\treturn id;\n}\n\nvoid ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\n\tIM_ASSERT(columns_count >= 1);\n\tIM_ASSERT(window->DC.CurrentColumns == NULL);   // Nested columns are currently not supported\n\n\t// Acquire storage for the columns set\n\tImGuiID id = GetColumnsID(str_id, columns_count);\n\tImGuiOldColumns* columns = FindOrCreateColumns(window, id);\n\tIM_ASSERT(columns->ID == id);\n\tcolumns->Current = 0;\n\tcolumns->Count = columns_count;\n\tcolumns->Flags = flags;\n\twindow->DC.CurrentColumns = columns;\n\twindow->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX();\n\n\tcolumns->HostCursorPosY = window->DC.CursorPos.y;\n\tcolumns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;\n\tcolumns->HostInitialClipRect = window->ClipRect;\n\tcolumns->HostBackupParentWorkRect = window->ParentWorkRect;\n\twindow->ParentWorkRect = window->WorkRect;\n\n\t// Set state for first column\n\t// We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect\n\tconst float column_padding = g.Style.ItemSpacing.x;\n\tconst float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize));\n\tconst float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f);\n\tconst float max_2 = window->WorkRect.Max.x + half_clip_extend_x;\n\tcolumns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f);\n\tcolumns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f);\n\tcolumns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;\n\n\t// Clear data if columns count changed\n\tif (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)\n\t\tcolumns->Columns.resize(0);\n\n\t// Initialize default widths\n\tcolumns->IsFirstFrame = (columns->Columns.Size == 0);\n\tif (columns->Columns.Size == 0)\n\t{\n\t\tcolumns->Columns.reserve(columns_count + 1);\n\t\tfor (int n = 0; n < columns_count + 1; n++)\n\t\t{\n\t\t\tImGuiOldColumnData column;\n\t\t\tcolumn.OffsetNorm = n / (float)columns_count;\n\t\t\tcolumns->Columns.push_back(column);\n\t\t}\n\t}\n\n\tfor (int n = 0; n < columns_count; n++)\n\t{\n\t\t// Compute clipping rectangle\n\t\tImGuiOldColumnData* column = &columns->Columns[n];\n\t\tfloat clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n));\n\t\tfloat clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f);\n\t\tcolumn->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);\n\t\tcolumn->ClipRect.ClipWithFull(window->ClipRect);\n\t}\n\n\tif (columns->Count > 1)\n\t{\n\t\tcolumns->Splitter.Split(window->DrawList, 1 + columns->Count);\n\t\tcolumns->Splitter.SetCurrentChannel(window->DrawList, 1);\n\t\tPushColumnClipRect(0);\n\t}\n\n\t// We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user.\n\tfloat offset_0 = GetColumnOffset(columns->Current);\n\tfloat offset_1 = GetColumnOffset(columns->Current + 1);\n\tfloat width = offset_1 - offset_0;\n\tPushItemWidth(width * 0.65f);\n\twindow->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);\n\twindow->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);\n\twindow->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;\n\twindow->WorkRect.Max.y = window->ContentRegionRect.Max.y;\n}\n\nvoid ImGui::NextColumn()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems || window->DC.CurrentColumns == NULL)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\n\tif (columns->Count == 1)\n\t{\n\t\twindow->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);\n\t\tIM_ASSERT(columns->Current == 0);\n\t\treturn;\n\t}\n\n\t// Next column\n\tif (++columns->Current == columns->Count)\n\t\tcolumns->Current = 0;\n\n\tPopItemWidth();\n\n\t// Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect()\n\t// (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them),\n\tImGuiOldColumnData* column = &columns->Columns[columns->Current];\n\tSetWindowClipRectBeforeSetChannel(window, column->ClipRect);\n\tcolumns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1);\n\n\tconst float column_padding = g.Style.ItemSpacing.x;\n\tcolumns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);\n\tif (columns->Current > 0)\n\t{\n\t\t// Columns 1+ ignore IndentX (by canceling it out)\n\t\t// FIXME-COLUMNS: Unnecessary, could be locked?\n\t\twindow->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding;\n\t}\n\telse\n\t{\n\t\t// New row/line: column 0 honor IndentX.\n\t\twindow->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);\n\t\twindow->DC.IsSameLine = false;\n\t\tcolumns->LineMinY = columns->LineMaxY;\n\t}\n\twindow->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);\n\twindow->DC.CursorPos.y = columns->LineMinY;\n\twindow->DC.CurrLineSize = ImVec2(0.0f, 0.0f);\n\twindow->DC.CurrLineTextBaseOffset = 0.0f;\n\n\t// FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup.\n\tfloat offset_0 = GetColumnOffset(columns->Current);\n\tfloat offset_1 = GetColumnOffset(columns->Current + 1);\n\tfloat width = offset_1 - offset_0;\n\tPushItemWidth(width * 0.65f);\n\twindow->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;\n}\n\nvoid ImGui::EndColumns()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tIM_ASSERT(columns != NULL);\n\n\tPopItemWidth();\n\tif (columns->Count > 1)\n\t{\n\t\tPopClipRect();\n\t\tcolumns->Splitter.Merge(window->DrawList);\n\t}\n\n\tconst ImGuiOldColumnFlags flags = columns->Flags;\n\tcolumns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);\n\twindow->DC.CursorPos.y = columns->LineMaxY;\n\tif (!(flags & ImGuiOldColumnFlags_GrowParentContentsSize))\n\t\twindow->DC.CursorMaxPos.x = columns->HostCursorMaxPosX;  // Restore cursor max pos, as columns don't grow parent\n\n\t// Draw columns borders and handle resize\n\t// The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy\n\tbool is_being_resized = false;\n\tif (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems)\n\t{\n\t\t// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.\n\t\tconst float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);\n\t\tconst float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);\n\t\tint dragging_column = -1;\n\t\tfor (int n = 1; n < columns->Count; n++)\n\t\t{\n\t\t\tImGuiOldColumnData* column = &columns->Columns[n];\n\t\t\tfloat x = window->Pos.x + GetColumnOffset(n);\n\t\t\tconst ImGuiID column_id = columns->ID + ImGuiID(n);\n\t\t\tconst float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;\n\t\t\tconst ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));\n\t\t\tif (!ItemAdd(column_hit_rect, column_id, NULL, ImGuiItemFlags_NoNav))\n\t\t\t\tcontinue;\n\n\t\t\tbool hovered = false, held = false;\n\t\t\tif (!(flags & ImGuiOldColumnFlags_NoResize))\n\t\t\t{\n\t\t\t\tButtonBehavior(column_hit_rect, column_id, &hovered, &held);\n\t\t\t\tif (hovered || held)\n\t\t\t\t\tg.MouseCursor = ImGuiMouseCursor_ResizeEW;\n\t\t\t\tif (held && !(column->Flags & ImGuiOldColumnFlags_NoResize))\n\t\t\t\t\tdragging_column = n;\n\t\t\t}\n\n\t\t\t// Draw column\n\t\t\tconst ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);\n\t\t\tconst float xi = IM_FLOOR(x);\n\t\t\twindow->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);\n\t\t}\n\n\t\t// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.\n\t\tif (dragging_column != -1)\n\t\t{\n\t\t\tif (!columns->IsBeingResized)\n\t\t\t\tfor (int n = 0; n < columns->Count + 1; n++)\n\t\t\t\t\tcolumns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;\n\t\t\tcolumns->IsBeingResized = is_being_resized = true;\n\t\t\tfloat x = GetDraggedColumnOffset(columns, dragging_column);\n\t\t\tSetColumnOffset(dragging_column, x);\n\t\t}\n\t}\n\tcolumns->IsBeingResized = is_being_resized;\n\n\twindow->WorkRect = window->ParentWorkRect;\n\twindow->ParentWorkRect = columns->HostBackupParentWorkRect;\n\twindow->DC.CurrentColumns = NULL;\n\twindow->DC.ColumnsOffset.x = 0.0f;\n\twindow->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);\n\tNavUpdateCurrentWindowIsScrollPushableX();\n}\n\nvoid ImGui::Columns(int columns_count, const char* id, bool border)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tIM_ASSERT(columns_count >= 1);\n\n\tImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder);\n\t//flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior\n\tImGuiOldColumns* columns = window->DC.CurrentColumns;\n\tif (columns != NULL && columns->Count == columns_count && columns->Flags == flags)\n\t\treturn;\n\n\tif (columns != NULL)\n\t\tEndColumns();\n\n\tif (columns_count != 1)\n\t\tBeginColumns(id, columns_count, flags);\n}\n\n//-------------------------------------------------------------------------\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imgui_widgets.cpp",
    "content": "// dear imgui, v1.89.9\n// (widgets code)\n\n/*\n\nIndex of this file:\n\n// [SECTION] Forward Declarations\n// [SECTION] Widgets: Text, etc.\n// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, Bullet, etc.)\n// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separator, etc.)\n// [SECTION] Widgets: ComboBox\n// [SECTION] Data Type and Data Formatting Helpers\n// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc.\n// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc.\n// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc.\n// [SECTION] Widgets: InputText, InputTextMultiline\n// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc.\n// [SECTION] Widgets: TreeNode, CollapsingHeader, etc.\n// [SECTION] Widgets: Selectable\n// [SECTION] Widgets: ListBox\n// [SECTION] Widgets: PlotLines, PlotHistogram\n// [SECTION] Widgets: Value helpers\n// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc.\n// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.\n// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.\n// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.\n\n*/\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#ifndef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS\n#endif\n\n#include \"imgui.h\"\n#ifndef IMGUI_DISABLE\n#include \"imgui_internal.h\"\n\n// System includes\n#include <stdint.h>     // intptr_t\n\n//-------------------------------------------------------------------------\n// Warnings\n//-------------------------------------------------------------------------\n\n// Visual Studio warnings\n#ifdef _MSC_VER\n#pragma warning (disable: 4127)     // condition expression is constant\n#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen\n#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later\n#pragma warning (disable: 5054)     // operator '|': deprecated between enumerations of different types\n#endif\n#pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).\n#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n#endif\n\n// Clang/GCC warnings with -Weverything\n#if defined(__clang__)\n#if __has_warning(\"-Wunknown-warning-option\")\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!\n#endif\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"                // warning: unknown warning group 'xxx'\n#pragma clang diagnostic ignored \"-Wold-style-cast\"                 // warning: use of old-style cast                            // yes, they are more terse.\n#pragma clang diagnostic ignored \"-Wfloat-equal\"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.\n#pragma clang diagnostic ignored \"-Wformat-nonliteral\"              // warning: format string is not a string literal            // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.\n#pragma clang diagnostic ignored \"-Wsign-conversion\"                // warning: implicit conversion changes signedness\n#pragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.\n#pragma clang diagnostic ignored \"-Wenum-enum-conversion\"           // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')\n#pragma clang diagnostic ignored \"-Wdeprecated-enum-enum-conversion\"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated\n#pragma clang diagnostic ignored \"-Wimplicit-int-float-conversion\"  // warning: implicit conversion from 'xxx' to 'float' may lose precision\n#elif defined(__GNUC__)\n#pragma GCC diagnostic ignored \"-Wpragmas\"                          // warning: unknown option after '#pragma GCC diagnostic' kind\n#pragma GCC diagnostic ignored \"-Wformat-nonliteral\"                // warning: format not a string literal, format string not checked\n#pragma GCC diagnostic ignored \"-Wclass-memaccess\"                  // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead\n#pragma GCC diagnostic ignored \"-Wdeprecated-enum-enum-conversion\"  // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated\n#endif\n\n//-------------------------------------------------------------------------\n// Data\n//-------------------------------------------------------------------------\n\n// Widgets\nstatic const float          DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f;    // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior.\nstatic const float          DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f;    // Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags.\n\n// Those MIN/MAX values are not define because we need to point to them\nstatic const signed char    IM_S8_MIN = -128;\nstatic const signed char    IM_S8_MAX = 127;\nstatic const unsigned char  IM_U8_MIN = 0;\nstatic const unsigned char  IM_U8_MAX = 0xFF;\nstatic const signed short   IM_S16_MIN = -32768;\nstatic const signed short   IM_S16_MAX = 32767;\nstatic const unsigned short IM_U16_MIN = 0;\nstatic const unsigned short IM_U16_MAX = 0xFFFF;\nstatic const ImS32          IM_S32_MIN = INT_MIN;    // (-2147483647 - 1), (0x80000000);\nstatic const ImS32          IM_S32_MAX = INT_MAX;    // (2147483647), (0x7FFFFFFF)\nstatic const ImU32          IM_U32_MIN = 0;\nstatic const ImU32          IM_U32_MAX = UINT_MAX;   // (0xFFFFFFFF)\n#ifdef LLONG_MIN\nstatic const ImS64          IM_S64_MIN = LLONG_MIN;  // (-9223372036854775807ll - 1ll);\nstatic const ImS64          IM_S64_MAX = LLONG_MAX;  // (9223372036854775807ll);\n#else\nstatic const ImS64          IM_S64_MIN = -9223372036854775807LL - 1;\nstatic const ImS64          IM_S64_MAX = 9223372036854775807LL;\n#endif\nstatic const ImU64          IM_U64_MIN = 0;\n#ifdef ULLONG_MAX\nstatic const ImU64          IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull);\n#else\nstatic const ImU64          IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);\n#endif\n\n//-------------------------------------------------------------------------\n// [SECTION] Forward Declarations\n//-------------------------------------------------------------------------\n\n// For InputTextEx()\nstatic bool             InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source);\nstatic int              InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);\nstatic ImVec2           InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: Text, etc.\n//-------------------------------------------------------------------------\n// - TextEx() [Internal]\n// - TextUnformatted()\n// - Text()\n// - TextV()\n// - TextColored()\n// - TextColoredV()\n// - TextDisabled()\n// - TextDisabledV()\n// - TextWrapped()\n// - TextWrappedV()\n// - LabelText()\n// - LabelTextV()\n// - BulletText()\n// - BulletTextV()\n//-------------------------------------------------------------------------\n\nvoid ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\tImGuiContext& g = *GImGui;\n\n\t// Accept null ranges\n\tif (text == text_end)\n\t\ttext = text_end = \"\";\n\n\t// Calculate length\n\tconst char* text_begin = text;\n\tif (text_end == NULL)\n\t\ttext_end = text + strlen(text); // FIXME-OPT\n\n\tconst ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);\n\tconst float wrap_pos_x = window->DC.TextWrapPos;\n\tconst bool wrap_enabled = (wrap_pos_x >= 0.0f);\n\tif (text_end - text <= 2000 || wrap_enabled)\n\t{\n\t\t// Common case\n\t\tconst float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;\n\t\tconst ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);\n\n\t\tImRect bb(text_pos, text_pos + text_size);\n\t\tItemSize(text_size, 0.0f);\n\t\tif (!ItemAdd(bb, 0))\n\t\t\treturn;\n\n\t\t// Render (we don't hide text after ## in this end-user function)\n\t\tRenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);\n\t}\n\telse\n\t{\n\t\t// Long text!\n\t\t// Perform manual coarse clipping to optimize for long multi-line text\n\t\t// - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.\n\t\t// - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.\n\t\t// - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop.\n\t\tconst char* line = text;\n\t\tconst float line_height = GetTextLineHeight();\n\t\tImVec2 text_size(0, 0);\n\n\t\t// Lines to skip (can't skip when logging text)\n\t\tImVec2 pos = text_pos;\n\t\tif (!g.LogEnabled)\n\t\t{\n\t\t\tint lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height);\n\t\t\tif (lines_skippable > 0)\n\t\t\t{\n\t\t\t\tint lines_skipped = 0;\n\t\t\t\twhile (line < text_end && lines_skipped < lines_skippable)\n\t\t\t\t{\n\t\t\t\t\tconst char* line_end = (const char*)memchr(line, '\\n', text_end - line);\n\t\t\t\t\tif (!line_end)\n\t\t\t\t\t\tline_end = text_end;\n\t\t\t\t\tif ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)\n\t\t\t\t\t\ttext_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);\n\t\t\t\t\tline = line_end + 1;\n\t\t\t\t\tlines_skipped++;\n\t\t\t\t}\n\t\t\t\tpos.y += lines_skipped * line_height;\n\t\t\t}\n\t\t}\n\n\t\t// Lines to render\n\t\tif (line < text_end)\n\t\t{\n\t\t\tImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));\n\t\t\twhile (line < text_end)\n\t\t\t{\n\t\t\t\tif (IsClippedEx(line_rect, 0))\n\t\t\t\t\tbreak;\n\n\t\t\t\tconst char* line_end = (const char*)memchr(line, '\\n', text_end - line);\n\t\t\t\tif (!line_end)\n\t\t\t\t\tline_end = text_end;\n\t\t\t\ttext_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);\n\t\t\t\tRenderText(pos, line, line_end, false);\n\t\t\t\tline = line_end + 1;\n\t\t\t\tline_rect.Min.y += line_height;\n\t\t\t\tline_rect.Max.y += line_height;\n\t\t\t\tpos.y += line_height;\n\t\t\t}\n\n\t\t\t// Count remaining lines\n\t\t\tint lines_skipped = 0;\n\t\t\twhile (line < text_end)\n\t\t\t{\n\t\t\t\tconst char* line_end = (const char*)memchr(line, '\\n', text_end - line);\n\t\t\t\tif (!line_end)\n\t\t\t\t\tline_end = text_end;\n\t\t\t\tif ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)\n\t\t\t\t\ttext_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);\n\t\t\t\tline = line_end + 1;\n\t\t\t\tlines_skipped++;\n\t\t\t}\n\t\t\tpos.y += lines_skipped * line_height;\n\t\t}\n\t\ttext_size.y = (pos - text_pos).y;\n\n\t\tImRect bb(text_pos, text_pos + text_size);\n\t\tItemSize(text_size, 0.0f);\n\t\tItemAdd(bb, 0);\n\t}\n}\n\nvoid ImGui::TextUnformatted(const char* text, const char* text_end)\n{\n\tTextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);\n}\n\nvoid ImGui::Text(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tTextV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::TextV(const char* fmt, va_list args)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tconst char* text, * text_end;\n\tImFormatStringToTempBufferV(&text, &text_end, fmt, args);\n\tTextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);\n}\n\nvoid ImGui::TextColored(const ImVec4& col, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tTextColoredV(col, fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)\n{\n\tPushStyleColor(ImGuiCol_Text, col);\n\tTextV(fmt, args);\n\tPopStyleColor();\n}\n\nvoid ImGui::TextDisabled(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tTextDisabledV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::TextDisabledV(const char* fmt, va_list args)\n{\n\tImGuiContext& g = *GImGui;\n\tPushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);\n\tTextV(fmt, args);\n\tPopStyleColor();\n}\n\nvoid ImGui::TextWrapped(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tTextWrappedV(fmt, args);\n\tva_end(args);\n}\n\nvoid ImGui::TextWrappedV(const char* fmt, va_list args)\n{\n\tImGuiContext& g = *GImGui;\n\tconst bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f);  // Keep existing wrap position if one is already set\n\tif (need_backup)\n\t\tPushTextWrapPos(0.0f);\n\tTextV(fmt, args);\n\tif (need_backup)\n\t\tPopTextWrapPos();\n}\n\nvoid ImGui::LabelText(const char* label, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tLabelTextV(label, fmt, args);\n\tva_end(args);\n}\n\n// Add a label+text combo aligned to other label+value widgets\nvoid ImGui::LabelTextV(const char* label, const char* fmt, va_list args)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst float w = CalcItemWidth();\n\n\tconst char* value_text_begin, * value_text_end;\n\tImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args);\n\tconst ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tconst ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2));\n\tconst ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2));\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, 0))\n\t\treturn;\n\n\t// Render\n\tRenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f));\n\tif (label_size.x > 0.0f)\n\t\tRenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);\n}\n\nvoid ImGui::BulletText(const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tBulletTextV(fmt, args);\n\tva_end(args);\n}\n\n// Text with a little bullet aligned to the typical tree node.\nvoid ImGui::BulletTextV(const char* fmt, va_list args)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\n\tconst char* text_begin, * text_end;\n\tImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args);\n\tconst ImVec2 label_size = CalcTextSize(text_begin, text_end, false);\n\tconst ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y);  // Empty text doesn't add padding\n\tImVec2 pos = window->DC.CursorPos;\n\tpos.y += window->DC.CurrLineTextBaseOffset;\n\tItemSize(total_size, 0.0f);\n\tconst ImRect bb(pos, pos + total_size);\n\tif (!ItemAdd(bb, 0))\n\t\treturn;\n\n\t// Render\n\tImU32 text_col = GetColorU32(ImGuiCol_Text);\n\tRenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col);\n\tRenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: Main\n//-------------------------------------------------------------------------\n// - ButtonBehavior() [Internal]\n// - Button()\n// - SmallButton()\n// - InvisibleButton()\n// - ArrowButton()\n// - CloseButton() [Internal]\n// - CollapseButton() [Internal]\n// - GetWindowScrollbarID() [Internal]\n// - GetWindowScrollbarRect() [Internal]\n// - Scrollbar() [Internal]\n// - ScrollbarEx() [Internal]\n// - Image()\n// - ImageButton()\n// - Checkbox()\n// - CheckboxFlagsT() [Internal]\n// - CheckboxFlags()\n// - RadioButton()\n// - ProgressBar()\n// - Bullet()\n//-------------------------------------------------------------------------\n\n// The ButtonBehavior() function is key to many interactions and used by many/most widgets.\n// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via ImGuiButtonFlags_),\n// this code is a little complex.\n// By far the most common path is interacting with the Mouse using the default ImGuiButtonFlags_PressedOnClickRelease button behavior.\n// See the series of events below and the corresponding state reported by dear imgui:\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// with PressedOnClickRelease:             return-value  IsItemHovered()  IsItemActive()  IsItemActivated()  IsItemDeactivated()  IsItemClicked()\n//   Frame N+0 (mouse is outside bb)        -             -                -               -                  -                    -\n//   Frame N+1 (mouse moves inside bb)      -             true             -               -                  -                    -\n//   Frame N+2 (mouse button is down)       -             true             true            true               -                    true\n//   Frame N+3 (mouse button is down)       -             true             true            -                  -                    -\n//   Frame N+4 (mouse moves outside bb)     -             -                true            -                  -                    -\n//   Frame N+5 (mouse moves inside bb)      -             true             true            -                  -                    -\n//   Frame N+6 (mouse button is released)   true          true             -               -                  true                 -\n//   Frame N+7 (mouse button is released)   -             true             -               -                  -                    -\n//   Frame N+8 (mouse moves outside bb)     -             -                -               -                  -                    -\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// with PressedOnClick:                    return-value  IsItemHovered()  IsItemActive()  IsItemActivated()  IsItemDeactivated()  IsItemClicked()\n//   Frame N+2 (mouse button is down)       true          true             true            true               -                    true\n//   Frame N+3 (mouse button is down)       -             true             true            -                  -                    -\n//   Frame N+6 (mouse button is released)   -             true             -               -                  true                 -\n//   Frame N+7 (mouse button is released)   -             true             -               -                  -                    -\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// with PressedOnRelease:                  return-value  IsItemHovered()  IsItemActive()  IsItemActivated()  IsItemDeactivated()  IsItemClicked()\n//   Frame N+2 (mouse button is down)       -             true             -               -                  -                    true\n//   Frame N+3 (mouse button is down)       -             true             -               -                  -                    -\n//   Frame N+6 (mouse button is released)   true          true             -               -                  -                    -\n//   Frame N+7 (mouse button is released)   -             true             -               -                  -                    -\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// with PressedOnDoubleClick:              return-value  IsItemHovered()  IsItemActive()  IsItemActivated()  IsItemDeactivated()  IsItemClicked()\n//   Frame N+0 (mouse button is down)       -             true             -               -                  -                    true\n//   Frame N+1 (mouse button is down)       -             true             -               -                  -                    -\n//   Frame N+2 (mouse button is released)   -             true             -               -                  -                    -\n//   Frame N+3 (mouse button is released)   -             true             -               -                  -                    -\n//   Frame N+4 (mouse button is down)       true          true             true            true               -                    true\n//   Frame N+5 (mouse button is down)       -             true             true            -                  -                    -\n//   Frame N+6 (mouse button is released)   -             true             -               -                  true                 -\n//   Frame N+7 (mouse button is released)   -             true             -               -                  -                    -\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// Note that some combinations are supported,\n// - PressedOnDragDropHold can generally be associated with any flag.\n// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported.\n//------------------------------------------------------------------------------------------------------------------------------------------------\n// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set:\n//                                         Repeat+                  Repeat+           Repeat+             Repeat+\n//                                         PressedOnClickRelease    PressedOnClick    PressedOnRelease    PressedOnDoubleClick\n//-------------------------------------------------------------------------------------------------------------------------------------------------\n//   Frame N+0 (mouse button is down)       -                        true              -                   true\n//   ...                                    -                        -                 -                   -\n//   Frame N + RepeatDelay                  true                     true              -                   true\n//   ...                                    -                        -                 -                   -\n//   Frame N + RepeatDelay + RepeatRate*N   true                     true              -                   true\n//-------------------------------------------------------------------------------------------------------------------------------------------------\n\nbool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\n\t// Default only reacts to left mouse button\n\tif ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0)\n\t\tflags |= ImGuiButtonFlags_MouseButtonDefault_;\n\n\t// Default behavior requires click + release inside bounding box\n\tif ((flags & ImGuiButtonFlags_PressedOnMask_) == 0)\n\t\tflags |= ImGuiButtonFlags_PressedOnDefault_;\n\n\t// Default behavior inherited from item flags\n\t// Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that.\n\tImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);\n\tif (flags & ImGuiButtonFlags_AllowOverlap)\n\t\titem_flags |= ImGuiItemFlags_AllowOverlap;\n\tif (flags & ImGuiButtonFlags_Repeat)\n\t\titem_flags |= ImGuiItemFlags_ButtonRepeat;\n\n\tImGuiWindow* backup_hovered_window = g.HoveredWindow;\n\tconst bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window;\n\tif (flatten_hovered_children)\n\t\tg.HoveredWindow = window;\n\n#ifdef IMGUI_ENABLE_TEST_ENGINE\n\t// Alternate registration spot, for when caller didn't use ItemAdd()\n\tif (id != 0 && g.LastItemData.ID != id)\n\t\tIMGUI_TEST_ENGINE_ITEM_ADD(id, bb, NULL);\n#endif\n\n\tbool pressed = false;\n\tbool hovered = ItemHoverable(bb, id, item_flags);\n\n\t// Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button\n\tif (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))\n\t\tif (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))\n\t\t{\n\t\t\thovered = true;\n\t\t\tSetHoveredID(id);\n\t\t\tif (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER)\n\t\t\t{\n\t\t\t\tpressed = true;\n\t\t\t\tg.DragDropHoldJustPressedId = id;\n\t\t\t\tFocusWindow(window);\n\t\t\t}\n\t\t}\n\n\tif (flatten_hovered_children)\n\t\tg.HoveredWindow = backup_hovered_window;\n\n\t// Mouse handling\n\tconst ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id;\n\tif (hovered)\n\t{\n\t\t// Poll mouse buttons\n\t\t// - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId.\n\t\t// - Technically we only need some values in one code path, but since this is gated by hovered test this is fine.\n\t\tint mouse_button_clicked = -1;\n\t\tint mouse_button_released = -1;\n\t\tfor (int button = 0; button < 3; button++)\n\t\t\tif (flags & (ImGuiButtonFlags_MouseButtonLeft << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here.\n\t\t\t{\n\t\t\t\tif (IsMouseClicked(button, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; }\n\t\t\t\tif (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; }\n\t\t\t}\n\n\t\t// Process initial action\n\t\tif (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))\n\t\t{\n\t\t\tif (mouse_button_clicked != -1 && g.ActiveId != id)\n\t\t\t{\n\t\t\t\tif (!(flags & ImGuiButtonFlags_NoSetKeyOwner))\n\t\t\t\t\tSetKeyOwner(MouseButtonToKey(mouse_button_clicked), id);\n\t\t\t\tif (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere))\n\t\t\t\t{\n\t\t\t\t\tSetActiveID(id, window);\n\t\t\t\t\tg.ActiveIdMouseButton = mouse_button_clicked;\n\t\t\t\t\tif (!(flags & ImGuiButtonFlags_NoNavFocus))\n\t\t\t\t\t\tSetFocusID(id, window);\n\t\t\t\t\tFocusWindow(window);\n\t\t\t\t}\n\t\t\t\tif ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2))\n\t\t\t\t{\n\t\t\t\t\tpressed = true;\n\t\t\t\t\tif (flags & ImGuiButtonFlags_NoHoldingActiveId)\n\t\t\t\t\t\tClearActiveID();\n\t\t\t\t\telse\n\t\t\t\t\t\tSetActiveID(id, window); // Hold on ID\n\t\t\t\t\tif (!(flags & ImGuiButtonFlags_NoNavFocus))\n\t\t\t\t\t\tSetFocusID(id, window);\n\t\t\t\t\tg.ActiveIdMouseButton = mouse_button_clicked;\n\t\t\t\t\tFocusWindow(window);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (flags & ImGuiButtonFlags_PressedOnRelease)\n\t\t\t{\n\t\t\t\tif (mouse_button_released != -1)\n\t\t\t\t{\n\t\t\t\t\tconst bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior\n\t\t\t\t\tif (!has_repeated_at_least_once)\n\t\t\t\t\t\tpressed = true;\n\t\t\t\t\tif (!(flags & ImGuiButtonFlags_NoNavFocus))\n\t\t\t\t\t\tSetFocusID(id, window);\n\t\t\t\t\tClearActiveID();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).\n\t\t\t// Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.\n\t\t\tif (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat))\n\t\t\t\tif (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat))\n\t\t\t\t\tpressed = true;\n\t\t}\n\n\t\tif (pressed)\n\t\t\tg.NavDisableHighlight = true;\n\t}\n\n\t// Gamepad/Keyboard navigation\n\t// We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse.\n\tif (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId))\n\t\tif (!(flags & ImGuiButtonFlags_NoHoveredOnFocus))\n\t\t\thovered = true;\n\tif (g.NavActivateDownId == id)\n\t{\n\t\tbool nav_activated_by_code = (g.NavActivateId == id);\n\t\tbool nav_activated_by_inputs = (g.NavActivatePressedId == id);\n\t\tif (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat))\n\t\t{\n\t\t\t// Avoid pressing multiple keys from triggering excessive amount of repeat events\n\t\t\tconst ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space);\n\t\t\tconst ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter);\n\t\t\tconst ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate);\n\t\t\tconst float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration);\n\t\t\tnav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;\n\t\t}\n\t\tif (nav_activated_by_code || nav_activated_by_inputs)\n\t\t{\n\t\t\t// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.\n\t\t\tpressed = true;\n\t\t\tSetActiveID(id, window);\n\t\t\tg.ActiveIdSource = g.NavInputSource;\n\t\t\tif (!(flags & ImGuiButtonFlags_NoNavFocus))\n\t\t\t\tSetFocusID(id, window);\n\t\t}\n\t}\n\n\t// Process while held\n\tbool held = false;\n\tif (g.ActiveId == id)\n\t{\n\t\tif (g.ActiveIdSource == ImGuiInputSource_Mouse)\n\t\t{\n\t\t\tif (g.ActiveIdIsJustActivated)\n\t\t\t\tg.ActiveIdClickOffset = g.IO.MousePos - bb.Min;\n\n\t\t\tconst int mouse_button = g.ActiveIdMouseButton;\n\t\t\tif (mouse_button == -1)\n\t\t\t{\n\t\t\t\t// Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304).\n\t\t\t\tClearActiveID();\n\t\t\t}\n\t\t\telse if (IsMouseDown(mouse_button, test_owner_id))\n\t\t\t{\n\t\t\t\theld = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0;\n\t\t\t\tbool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0;\n\t\t\t\tif ((release_in || release_anywhere) && !g.DragDropActive)\n\t\t\t\t{\n\t\t\t\t\t// Report as pressed when releasing the mouse (this is the most common path)\n\t\t\t\t\tbool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2;\n\t\t\t\t\tbool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps <on release>\n\t\t\t\t\tbool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id);\n\t\t\t\t\tif (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned)\n\t\t\t\t\t\tpressed = true;\n\t\t\t\t}\n\t\t\t\tClearActiveID();\n\t\t\t}\n\t\t\tif (!(flags & ImGuiButtonFlags_NoNavFocus))\n\t\t\t\tg.NavDisableHighlight = true;\n\t\t}\n\t\telse if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)\n\t\t{\n\t\t\t// When activated using Nav, we hold on the ActiveID until activation button is released\n\t\t\tif (g.NavActivateDownId != id)\n\t\t\t\tClearActiveID();\n\t\t}\n\t\tif (pressed)\n\t\t\tg.ActiveIdHasBeenPressedBefore = true;\n\t}\n\n\tif (out_hovered) *out_hovered = hovered;\n\tif (out_held) *out_held = held;\n\n\treturn pressed;\n}\n\nbool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\tImVec2 pos = window->DC.CursorPos;\n\tif ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)\n\t\tpos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;\n\tImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);\n\n\tconst ImRect bb(pos, pos + size);\n\tItemSize(size, style.FramePadding.y);\n\tif (!ItemAdd(bb, id))\n\t\treturn false;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);\n\n\t// Render\n\tconst ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\tRenderNavHighlight(bb, id);\n\tRenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);\n\n\tif (g.LogEnabled)\n\t\tLogSetNextTextDecoration(\"[\", \"]\");\n\tRenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);\n\n\t// Automatically close popups\n\t//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))\n\t//    CloseCurrentPopup();\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);\n\treturn pressed;\n}\n\nbool ImGui::Button(const char* label, const ImVec2& size_arg)\n{\n\treturn ButtonEx(label, size_arg, ImGuiButtonFlags_None);\n}\n\n// Small buttons fits within text without additional vertical spacing.\nbool ImGui::SmallButton(const char* label)\n{\n\tImGuiContext& g = *GImGui;\n\tfloat backup_padding_y = g.Style.FramePadding.y;\n\tg.Style.FramePadding.y = 0.0f;\n\tbool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine);\n\tg.Style.FramePadding.y = backup_padding_y;\n\treturn pressed;\n}\n\n// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.\n// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id)\nbool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\t// Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size.\n\tIM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f);\n\n\tconst ImGuiID id = window->GetID(str_id);\n\tImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tItemSize(size);\n\tif (!ItemAdd(bb, id))\n\t\treturn false;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags);\n\treturn pressed;\n}\n\nbool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst ImGuiID id = window->GetID(str_id);\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tconst float default_size = GetFrameHeight();\n\tItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f);\n\tif (!ItemAdd(bb, id))\n\t\treturn false;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);\n\n\t// Render\n\tconst ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\tconst ImU32 text_col = GetColorU32(ImGuiCol_Text);\n\tRenderNavHighlight(bb, id);\n\tRenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding);\n\tRenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags);\n\treturn pressed;\n}\n\nbool ImGui::ArrowButton(const char* str_id, ImGuiDir dir)\n{\n\tfloat sz = GetFrameHeight();\n\treturn ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None);\n}\n\n// Button to close a window\nbool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825)\n\t// This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible?\n\tconst ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));\n\tImRect bb_interact = bb;\n\tconst float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();\n\tif (area_to_visible_ratio < 1.5f)\n\t\tbb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f));\n\n\t// Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window.\n\t// (this isn't the common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer).\n\tbool is_clipped = !ItemAdd(bb_interact, id);\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb_interact, id, &hovered, &held);\n\tif (is_clipped)\n\t\treturn pressed;\n\n\t// Render\n\t// FIXME: Clarify this mess\n\tImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);\n\tImVec2 center = bb.GetCenter();\n\tif (hovered)\n\t\twindow->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col);\n\n\tfloat cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;\n\tImU32 cross_col = GetColorU32(ImGuiCol_Text);\n\tcenter -= ImVec2(0.5f, 0.5f);\n\twindow->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f);\n\twindow->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f);\n\n\treturn pressed;\n}\n\nbool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));\n\tbool is_clipped = !ItemAdd(bb, id);\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);\n\tif (is_clipped)\n\t\treturn pressed;\n\n\t// Render\n\tImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\tImU32 text_col = GetColorU32(ImGuiCol_Text);\n\tif (hovered || held)\n\t\twindow->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, bg_col);\n\tRenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);\n\n\t// Switch to moving the window after mouse is moved beyond the initial drag threshold\n\tif (IsItemActive() && IsMouseDragging(0))\n\t\tStartMouseMovingWindow(window);\n\n\treturn pressed;\n}\n\nImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis)\n{\n\treturn window->GetID(axis == ImGuiAxis_X ? \"#SCROLLX\" : \"#SCROLLY\");\n}\n\n// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set.\nImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)\n{\n\tconst ImRect outer_rect = window->Rect();\n\tconst ImRect inner_rect = window->InnerRect;\n\tconst float border_size = window->WindowBorderSize;\n\tconst float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar)\n\tIM_ASSERT(scrollbar_size > 0.0f);\n\tif (axis == ImGuiAxis_X)\n\t\treturn ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size);\n\telse\n\t\treturn ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size);\n}\n\nvoid ImGui::Scrollbar(ImGuiAxis axis)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tconst ImGuiID id = GetWindowScrollbarID(window, axis);\n\n\t// Calculate scrollbar bounding box\n\tImRect bb = GetWindowScrollbarRect(window, axis);\n\tImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone;\n\tif (axis == ImGuiAxis_X)\n\t{\n\t\trounding_corners |= ImDrawFlags_RoundCornersBottomLeft;\n\t\tif (!window->ScrollbarY)\n\t\t\trounding_corners |= ImDrawFlags_RoundCornersBottomRight;\n\t}\n\telse\n\t{\n\t\tif ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar))\n\t\t\trounding_corners |= ImDrawFlags_RoundCornersTopRight;\n\t\tif (!window->ScrollbarX)\n\t\t\trounding_corners |= ImDrawFlags_RoundCornersBottomRight;\n\t}\n\tfloat size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis];\n\tfloat size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f;\n\tImS64 scroll = (ImS64)window->Scroll[axis];\n\tScrollbarEx(bb, id, axis, &scroll, (ImS64)size_avail, (ImS64)size_contents, rounding_corners);\n\twindow->Scroll[axis] = (float)scroll;\n}\n\n// Vertical/Horizontal scrollbar\n// The entire piece of code below is rather confusing because:\n// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)\n// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar\n// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.\n// Still, the code should probably be made simpler..\nbool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_avail_v, ImS64 size_contents_v, ImDrawFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst float bb_frame_width = bb_frame.GetWidth();\n\tconst float bb_frame_height = bb_frame.GetHeight();\n\tif (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f)\n\t\treturn false;\n\n\t// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab)\n\tfloat alpha = 1.0f;\n\tif ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f)\n\t\talpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));\n\tif (alpha <= 0.0f)\n\t\treturn false;\n\n\tconst ImGuiStyle& style = g.Style;\n\tconst bool allow_interaction = (alpha >= 1.0f);\n\n\tImRect bb = bb_frame;\n\tbb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f)));\n\n\t// V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)\n\tconst float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight();\n\n\t// Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)\n\t// But we maintain a minimum size in pixel to allow for the user to still aim inside.\n\tIM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.\n\tconst ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), (ImS64)1);\n\tconst float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_avail_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v);\n\tconst float grab_h_norm = grab_h_pixels / scrollbar_size_v;\n\n\t// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().\n\tbool held = false;\n\tbool hovered = false;\n\tItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav);\n\tButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);\n\n\tconst ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_avail_v);\n\tfloat scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max);\n\tfloat grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space\n\tif (held && allow_interaction && grab_h_norm < 1.0f)\n\t{\n\t\tconst float scrollbar_pos_v = bb.Min[axis];\n\t\tconst float mouse_pos_v = g.IO.MousePos[axis];\n\n\t\t// Click position in scrollbar normalized space (0.0f->1.0f)\n\t\tconst float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);\n\t\tSetHoveredID(id);\n\n\t\tbool seek_absolute = false;\n\t\tif (g.ActiveIdIsJustActivated)\n\t\t{\n\t\t\t// On initial click calculate the distance between mouse and the center of the grab\n\t\t\tseek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm);\n\t\t\tif (seek_absolute)\n\t\t\t\tg.ScrollbarClickDeltaToGrabCenter = 0.0f;\n\t\t\telse\n\t\t\t\tg.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;\n\t\t}\n\n\t\t// Apply scroll (p_scroll_v will generally point on one member of window->Scroll)\n\t\t// It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position\n\t\tconst float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm));\n\t\t*p_scroll_v = (ImS64)(scroll_v_norm * scroll_max);\n\n\t\t// Update values for rendering\n\t\tscroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max);\n\t\tgrab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;\n\n\t\t// Update distance to grab now that we have seeked and saturated\n\t\tif (seek_absolute)\n\t\t\tg.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;\n\t}\n\n\t// Render\n\tconst ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg);\n\tconst ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha);\n\twindow->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags);\n\tImRect grab_rect;\n\tif (axis == ImGuiAxis_X)\n\t\tgrab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y);\n\telse\n\t\tgrab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels);\n\twindow->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);\n\n\treturn held;\n}\n\nvoid ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tif (border_col.w > 0.0f)\n\t\tbb.Max += ImVec2(2, 2);\n\tItemSize(bb);\n\tif (!ItemAdd(bb, 0))\n\t\treturn;\n\n\tif (border_col.w > 0.0f)\n\t{\n\t\twindow->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);\n\t\twindow->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col));\n\t}\n\telse\n\t{\n\t\twindow->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));\n\t}\n}\n\n// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390)\n// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API.\nbool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst ImVec2 padding = g.Style.FramePadding;\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2.0f);\n\tItemSize(bb);\n\tif (!ItemAdd(bb, id))\n\t\treturn false;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);\n\n\t// Render\n\tconst ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\tRenderNavHighlight(bb, id);\n\tRenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding));\n\tif (bg_col.w > 0.0f)\n\t\twindow->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col));\n\twindow->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));\n\n\treturn pressed;\n}\n\nbool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\treturn ImageButtonEx(window->GetID(str_id), user_texture_id, size, uv0, uv1, bg_col, tint_col);\n}\n\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n// Legacy API obsoleted in 1.89. Two differences with new ImageButton()\n// - new ImageButton() requires an explicit 'const char* str_id'    Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID)\n// - new ImageButton() always use style.FramePadding                Old ImageButton() had an override argument.\n// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions.\nbool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\t// Default to using texture ID as ID. User can still push string/integer prefixes.\n\tPushID((void*)(intptr_t)user_texture_id);\n\tconst ImGuiID id = window->GetID(\"#image\");\n\tPopID();\n\n\tif (frame_padding >= 0)\n\t\tPushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding));\n\tbool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col);\n\tif (frame_padding >= 0)\n\t\tPopStyleVar();\n\treturn ret;\n}\n#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\nbool ImGui::Checkbox(const char* label, bool* v)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\tconst float square_sz = GetFrameHeight();\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tconst ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, id))\n\t{\n\t\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));\n\t\treturn false;\n\t}\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(total_bb, id, &hovered, &held);\n\tif (pressed)\n\t{\n\t\t*v = !(*v);\n\t\tMarkItemEdited(id);\n\t}\n\n\tconst ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));\n\tRenderNavHighlight(total_bb, id);\n\tRenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);\n\tImU32 check_col = GetColorU32(ImGuiCol_CheckMark);\n\tbool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;\n\tif (mixed_value)\n\t{\n\t\t// Undocumented tristate/mixed/indeterminate checkbox (#2644)\n\t\t// This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)\n\t\tImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)));\n\t\twindow->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);\n\t}\n\telse if (*v)\n\t{\n\t\tconst float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));\n\t\tRenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);\n\t}\n\n\tImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);\n\tif (g.LogEnabled)\n\t\tLogRenderedText(&label_pos, mixed_value ? \"[~]\" : *v ? \"[x]\" : \"[ ]\");\n\tif (label_size.x > 0.0f)\n\t\tRenderText(label_pos, label);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));\n\treturn pressed;\n}\n\ntemplate<typename T>\nbool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value)\n{\n\tbool all_on = (*flags & flags_value) == flags_value;\n\tbool any_on = (*flags & flags_value) != 0;\n\tbool pressed;\n\tif (!all_on && any_on)\n\t{\n\t\tImGuiContext& g = *GImGui;\n\t\tg.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue;\n\t\tpressed = Checkbox(label, &all_on);\n\t}\n\telse\n\t{\n\t\tpressed = Checkbox(label, &all_on);\n\t}\n\tif (pressed)\n\t{\n\t\tif (all_on)\n\t\t\t*flags |= flags_value;\n\t\telse\n\t\t\t*flags &= ~flags_value;\n\t}\n\treturn pressed;\n}\n\nbool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value)\n{\n\treturn CheckboxFlagsT(label, flags, flags_value);\n}\n\nbool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)\n{\n\treturn CheckboxFlagsT(label, flags, flags_value);\n}\n\nbool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value)\n{\n\treturn CheckboxFlagsT(label, flags, flags_value);\n}\n\nbool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value)\n{\n\treturn CheckboxFlagsT(label, flags, flags_value);\n}\n\nbool ImGui::RadioButton(const char* label, bool active)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\tconst float square_sz = GetFrameHeight();\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tconst ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));\n\tconst ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, id))\n\t\treturn false;\n\n\tImVec2 center = check_bb.GetCenter();\n\tcenter.x = IM_ROUND(center.x);\n\tcenter.y = IM_ROUND(center.y);\n\tconst float radius = (square_sz - 1.0f) * 0.5f;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(total_bb, id, &hovered, &held);\n\tif (pressed)\n\t\tMarkItemEdited(id);\n\n\tRenderNavHighlight(total_bb, id);\n\tconst int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius);\n\twindow->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment);\n\tif (active)\n\t{\n\t\tconst float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));\n\t\twindow->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark));\n\t}\n\n\tif (style.FrameBorderSize > 0.0f)\n\t{\n\t\twindow->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize);\n\t\twindow->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize);\n\t}\n\n\tImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);\n\tif (g.LogEnabled)\n\t\tLogRenderedText(&label_pos, active ? \"(x)\" : \"( )\");\n\tif (label_size.x > 0.0f)\n\t\tRenderText(label_pos, label);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);\n\treturn pressed;\n}\n\n// FIXME: This would work nicely if it was a public template, e.g. 'template<T> RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it..\nbool ImGui::RadioButton(const char* label, int* v, int v_button)\n{\n\tconst bool pressed = RadioButton(label, *v == v_button);\n\tif (pressed)\n\t\t*v = v_button;\n\treturn pressed;\n}\n\n// size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size\nvoid ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f);\n\tImRect bb(pos, pos + size);\n\tItemSize(size, style.FramePadding.y);\n\tif (!ItemAdd(bb, 0))\n\t\treturn;\n\n\t// Render\n\tfraction = ImSaturate(fraction);\n\tRenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);\n\tbb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));\n\tconst ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);\n\tRenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);\n\n\t// Default displaying the fraction as percentage string, but user can override it\n\tchar overlay_buf[32];\n\tif (!overlay)\n\t{\n\t\tImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), \"%.0f%%\", fraction * 100 + 0.01f);\n\t\toverlay = overlay_buf;\n\t}\n\n\tImVec2 overlay_size = CalcTextSize(overlay, NULL);\n\tif (overlay_size.x > 0.0f)\n\t\tRenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);\n}\n\nvoid ImGui::Bullet()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize);\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));\n\tItemSize(bb);\n\tif (!ItemAdd(bb, 0))\n\t{\n\t\tSameLine(0, style.FramePadding.x * 2);\n\t\treturn;\n\t}\n\n\t// Render and stay on same line\n\tImU32 text_col = GetColorU32(ImGuiCol_Text);\n\tRenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), text_col);\n\tSameLine(0, style.FramePadding.x * 2.0f);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: Low-level Layout helpers\n//-------------------------------------------------------------------------\n// - Spacing()\n// - Dummy()\n// - NewLine()\n// - AlignTextToFramePadding()\n// - SeparatorEx() [Internal]\n// - Separator()\n// - SplitterBehavior() [Internal]\n// - ShrinkWidths() [Internal]\n//-------------------------------------------------------------------------\n\nvoid ImGui::Spacing()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\tItemSize(ImVec2(0, 0));\n}\n\nvoid ImGui::Dummy(const ImVec2& size)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tItemSize(size);\n\tItemAdd(bb, 0);\n}\n\nvoid ImGui::NewLine()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiLayoutType backup_layout_type = window->DC.LayoutType;\n\twindow->DC.LayoutType = ImGuiLayoutType_Vertical;\n\twindow->DC.IsSameLine = false;\n\tif (window->DC.CurrLineSize.y > 0.0f)     // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.\n\t\tItemSize(ImVec2(0, 0));\n\telse\n\t\tItemSize(ImVec2(0.0f, g.FontSize));\n\twindow->DC.LayoutType = backup_layout_type;\n}\n\nvoid ImGui::AlignTextToFramePadding()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\twindow->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2);\n\twindow->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y);\n}\n\n// Horizontal/vertical separating line\n// FIXME: Surprisingly, this seemingly trivial widget is a victim of many different legacy/tricky layout issues.\n// Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are.\nvoid ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)));   // Check that only 1 option is selected\n\tIM_ASSERT(thickness > 0.0f);\n\n\tif (flags & ImGuiSeparatorFlags_Vertical)\n\t{\n\t\t// Vertical separator, for menu bars (use current line height).\n\t\tfloat y1 = window->DC.CursorPos.y;\n\t\tfloat y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y;\n\t\tconst ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2));\n\t\tItemSize(ImVec2(thickness, 0.0f));\n\t\tif (!ItemAdd(bb, 0))\n\t\t\treturn;\n\n\t\t// Draw\n\t\twindow->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));\n\t\tif (g.LogEnabled)\n\t\t\tLogText(\" |\");\n\t}\n\telse if (flags & ImGuiSeparatorFlags_Horizontal)\n\t{\n\t\t// Horizontal Separator\n\t\tfloat x1 = window->Pos.x;\n\t\tfloat x2 = window->Pos.x + window->Size.x;\n\n\t\t// FIXME-WORKRECT: old hack (#205) until we decide of consistent behavior with WorkRect/Indent and Separator\n\t\tif (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID)\n\t\t\tx1 += window->DC.Indent.x;\n\n\t\t// FIXME-WORKRECT: In theory we should simply be using WorkRect.Min.x/Max.x everywhere but it isn't aesthetically what we want,\n\t\t// need to introduce a variant of WorkRect for that purpose. (#4787)\n\t\tif (ImGuiTable* table = g.CurrentTable)\n\t\t{\n\t\t\tx1 = table->Columns[table->CurrentColumn].MinX;\n\t\t\tx2 = table->Columns[table->CurrentColumn].MaxX;\n\t\t}\n\n\t\t// Before Tables API happened, we relied on Separator() to span all columns of a Columns() set.\n\t\t// We currently don't need to provide the same feature for tables because tables naturally have border features.\n\t\tImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL;\n\t\tif (columns)\n\t\t\tPushColumnsBackground();\n\n\t\t// We don't provide our width to the layout so that it doesn't get feed back into AutoFit\n\t\t// FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell)\n\t\tconst float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change.\n\t\tconst ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness));\n\t\tItemSize(ImVec2(0.0f, thickness_for_layout));\n\n\t\tif (ItemAdd(bb, 0))\n\t\t{\n\t\t\t// Draw\n\t\t\twindow->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));\n\t\t\tif (g.LogEnabled)\n\t\t\t\tLogRenderedText(&bb.Min, \"--------------------------------\\n\");\n\t\t}\n\t\tif (columns)\n\t\t{\n\t\t\tPopColumnsBackground();\n\t\t\tcolumns->LineMinY = window->DC.CursorPos.y;\n\t\t}\n\t}\n}\n\nvoid ImGui::Separator()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\t// Those flags should eventually be configurable by the user\n\t// FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f.\n\tImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;\n\tflags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot.\n\tSeparatorEx(flags, 1.0f);\n}\n\nvoid ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiStyle& style = g.Style;\n\n\tconst ImVec2 label_size = CalcTextSize(label, label_end, false);\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tconst ImVec2 padding = style.SeparatorTextPadding;\n\n\tconst float separator_thickness = style.SeparatorTextBorderSize;\n\tconst ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness));\n\tconst ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y));\n\tconst float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f));\n\tItemSize(min_size, text_baseline_y);\n\tif (!ItemAdd(bb, id))\n\t\treturn;\n\n\tconst float sep1_x1 = pos.x;\n\tconst float sep2_x2 = bb.Max.x;\n\tconst float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f);\n\n\tconst float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f);\n\tconst ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN\n\n\t// This allows using SameLine() to position something in the 'extra_w'\n\twindow->DC.CursorPosPrevLine.x = label_pos.x + label_size.x;\n\n\tconst ImU32 separator_col = GetColorU32(ImGuiCol_Separator);\n\tif (label_size.x > 0.0f)\n\t{\n\t\tconst float sep1_x2 = label_pos.x - style.ItemSpacing.x;\n\t\tconst float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x;\n\t\tif (sep1_x2 > sep1_x1 && separator_thickness > 0.0f)\n\t\t\twindow->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness);\n\t\tif (sep2_x2 > sep2_x1 && separator_thickness > 0.0f)\n\t\t\twindow->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);\n\t\tif (g.LogEnabled)\n\t\t\tLogSetNextTextDecoration(\"---\", NULL);\n\t\tRenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size);\n\t}\n\telse\n\t{\n\t\tif (g.LogEnabled)\n\t\t\tLogText(\"---\");\n\t\tif (separator_thickness > 0.0f)\n\t\t\twindow->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);\n\t}\n}\n\nvoid ImGui::SeparatorText(const char* label)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\t// The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want:\n\t// - allow separator-text to be draggable items (would require a stable ID + a noticeable highlight)\n\t// - this high-level entry point to allow formatting? (which in turns may require ID separate from formatted string)\n\t// - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...'\n\t// Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item,\n\t// and then we can turn this into a format function.\n\tSeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f);\n}\n\n// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise.\nbool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tif (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav))\n\t\treturn false;\n\n\t// FIXME: AFAIK the only leftover reason for passing ImGuiButtonFlags_AllowOverlap here is\n\t// to allow caller of SplitterBehavior() to call SetItemAllowOverlap() after the item.\n\t// Nowadays we would instead want to use SetNextItemAllowOverlap() before the item.\n\tImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren;\n#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\tbutton_flags |= ImGuiButtonFlags_AllowOverlap;\n#endif\n\n\tbool hovered, held;\n\tImRect bb_interact = bb;\n\tbb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));\n\tButtonBehavior(bb_interact, id, &hovered, &held, button_flags);\n\tif (hovered)\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb\n\n\tif (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay))\n\t\tSetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW);\n\n\tImRect bb_render = bb;\n\tif (held)\n\t{\n\t\tImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min;\n\t\tfloat mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x;\n\n\t\t// Minimum pane size\n\t\tfloat size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1);\n\t\tfloat size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2);\n\t\tif (mouse_delta < -size_1_maximum_delta)\n\t\t\tmouse_delta = -size_1_maximum_delta;\n\t\tif (mouse_delta > size_2_maximum_delta)\n\t\t\tmouse_delta = size_2_maximum_delta;\n\n\t\t// Apply resize\n\t\tif (mouse_delta != 0.0f)\n\t\t{\n\t\t\tif (mouse_delta < 0.0f)\n\t\t\t\tIM_ASSERT(*size1 + mouse_delta >= min_size1);\n\t\t\tif (mouse_delta > 0.0f)\n\t\t\t\tIM_ASSERT(*size2 - mouse_delta >= min_size2);\n\t\t\t*size1 += mouse_delta;\n\t\t\t*size2 -= mouse_delta;\n\t\t\tbb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta));\n\t\t\tMarkItemEdited(id);\n\t\t}\n\t}\n\n\t// Render at new position\n\tif (bg_col & IM_COL32_A_MASK)\n\t\twindow->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f);\n\tconst ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);\n\twindow->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f);\n\n\treturn held;\n}\n\nstatic int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)\n{\n\tconst ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs;\n\tconst ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs;\n\tif (int d = (int)(b->Width - a->Width))\n\t\treturn d;\n\treturn (b->Index - a->Index);\n}\n\n// Shrink excess width from a set of item, by removing width from the larger items first.\n// Set items Width to -1.0f to disable shrinking this item.\nvoid ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)\n{\n\tif (count == 1)\n\t{\n\t\tif (items[0].Width >= 0.0f)\n\t\t\titems[0].Width = ImMax(items[0].Width - width_excess, 1.0f);\n\t\treturn;\n\t}\n\tImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);\n\tint count_same_width = 1;\n\twhile (width_excess > 0.0f && count_same_width < count)\n\t{\n\t\twhile (count_same_width < count && items[0].Width <= items[count_same_width].Width)\n\t\t\tcount_same_width++;\n\t\tfloat max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);\n\t\tif (max_width_to_remove_per_item <= 0.0f)\n\t\t\tbreak;\n\t\tfloat width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);\n\t\tfor (int item_n = 0; item_n < count_same_width; item_n++)\n\t\t\titems[item_n].Width -= width_to_remove_per_item;\n\t\twidth_excess -= width_to_remove_per_item * count_same_width;\n\t}\n\n\t// Round width and redistribute remainder\n\t// Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator.\n\twidth_excess = 0.0f;\n\tfor (int n = 0; n < count; n++)\n\t{\n\t\tfloat width_rounded = ImFloor(items[n].Width);\n\t\twidth_excess += items[n].Width - width_rounded;\n\t\titems[n].Width = width_rounded;\n\t}\n\twhile (width_excess > 0.0f)\n\t\tfor (int n = 0; n < count && width_excess > 0.0f; n++)\n\t\t{\n\t\t\tfloat width_to_add = ImMin(items[n].InitialWidth - items[n].Width, 1.0f);\n\t\t\titems[n].Width += width_to_add;\n\t\t\twidth_excess -= width_to_add;\n\t\t}\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: ComboBox\n//-------------------------------------------------------------------------\n// - CalcMaxPopupHeightFromItemCount() [Internal]\n// - BeginCombo()\n// - BeginComboPopup() [Internal]\n// - EndCombo()\n// - BeginComboPreview() [Internal]\n// - EndComboPreview() [Internal]\n// - Combo()\n//-------------------------------------------------------------------------\n\nstatic float CalcMaxPopupHeightFromItemCount(int items_count)\n{\n\tImGuiContext& g = *GImGui;\n\tif (items_count <= 0)\n\t\treturn FLT_MAX;\n\treturn (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2);\n}\n\nbool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\n\tImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags;\n\tg.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tIM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together\n\n\tconst float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth();\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));\n\tconst ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, id, &bb))\n\t\treturn false;\n\n\t// Open on click\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held);\n\tconst ImGuiID popup_id = ImHashStr(\"##ComboPopup\", 0, id);\n\tbool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None);\n\tif (pressed && !popup_open)\n\t{\n\t\tOpenPopupEx(popup_id, ImGuiPopupFlags_None);\n\t\tpopup_open = true;\n\t}\n\n\t// Render shape\n\tconst ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);\n\tconst float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size);\n\tRenderNavHighlight(bb, id);\n\tif (!(flags & ImGuiComboFlags_NoPreview))\n\t\twindow->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft);\n\tif (!(flags & ImGuiComboFlags_NoArrowButton))\n\t{\n\t\tImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button);\n\t\tImU32 text_col = GetColorU32(ImGuiCol_Text);\n\t\twindow->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight);\n\t\tif (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x)\n\t\t\tRenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f);\n\t}\n\tRenderFrameBorder(bb.Min, bb.Max, style.FrameRounding);\n\n\t// Custom preview\n\tif (flags & ImGuiComboFlags_CustomPreview)\n\t{\n\t\tg.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);\n\t\tIM_ASSERT(preview_value == NULL || preview_value[0] == 0);\n\t\tpreview_value = NULL;\n\t}\n\n\t// Render preview and label\n\tif (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))\n\t{\n\t\tif (g.LogEnabled)\n\t\t\tLogSetNextTextDecoration(\"{\", \"}\");\n\t\tRenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL);\n\t}\n\tif (label_size.x > 0)\n\t\tRenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label);\n\n\tif (!popup_open)\n\t\treturn false;\n\n\tg.NextWindowData.Flags = backup_next_window_data_flags;\n\treturn BeginComboPopup(popup_id, bb, flags);\n}\n\nbool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif (!IsPopupOpen(popup_id, ImGuiPopupFlags_None))\n\t{\n\t\tg.NextWindowData.ClearFlags();\n\t\treturn false;\n\t}\n\n\t// Set popup size\n\tfloat w = bb.GetWidth();\n\tif (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)\n\t{\n\t\tg.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);\n\t}\n\telse\n\t{\n\t\tif ((flags & ImGuiComboFlags_HeightMask_) == 0)\n\t\t\tflags |= ImGuiComboFlags_HeightRegular;\n\t\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one\n\t\tint popup_max_height_in_items = -1;\n\t\tif (flags & ImGuiComboFlags_HeightRegular)     popup_max_height_in_items = 8;\n\t\telse if (flags & ImGuiComboFlags_HeightSmall)  popup_max_height_in_items = 4;\n\t\telse if (flags & ImGuiComboFlags_HeightLarge)  popup_max_height_in_items = 20;\n\t\tImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);\n\t\tif ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size\n\t\t\tconstraint_min.x = w;\n\t\tif ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)\n\t\t\tconstraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);\n\t\tSetNextWindowSizeConstraints(constraint_min, constraint_max);\n\t}\n\n\t// This is essentially a specialized version of BeginPopupEx()\n\tchar name[16];\n\tImFormatString(name, IM_ARRAYSIZE(name), \"##Combo_%02d\", g.BeginPopupStack.Size); // Recycle windows based on depth\n\n\t// Set position given a custom constraint (peak into expected window size so we can position it)\n\t// FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function?\n\t// FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()?\n\tif (ImGuiWindow* popup_window = FindWindowByName(name))\n\t\tif (popup_window->WasActive)\n\t\t{\n\t\t\t// Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us.\n\t\t\tImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window);\n\t\t\tpopup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = \"Below, Toward Left\", Down = \"Below, Toward Right (default)\"\n\t\t\tImRect r_outer = GetPopupAllowedExtentRect(popup_window);\n\t\t\tImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox);\n\t\t\tSetNextWindowPos(pos);\n\t\t}\n\n\t// We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx()\n\tImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove;\n\tPushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text\n\tbool ret = Begin(name, NULL, window_flags);\n\tPopStyleVar();\n\tif (!ret)\n\t{\n\t\tEndPopup();\n\t\tIM_ASSERT(0);   // This should never happen as we tested for IsPopupOpen() above\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid ImGui::EndCombo()\n{\n\tEndPopup();\n}\n\n// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements\n// (Experimental, see GitHub issues: #1658, #4168)\nbool ImGui::BeginComboPreview()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiComboPreviewData* preview_data = &g.ComboPreviewData;\n\n\tif (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible))\n\t\treturn false;\n\tIM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag?\n\tif (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional)\n\t\treturn false;\n\n\t// FIXME: This could be contained in a PushWorkRect() api\n\tpreview_data->BackupCursorPos = window->DC.CursorPos;\n\tpreview_data->BackupCursorMaxPos = window->DC.CursorMaxPos;\n\tpreview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine;\n\tpreview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;\n\tpreview_data->BackupLayout = window->DC.LayoutType;\n\twindow->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding;\n\twindow->DC.CursorMaxPos = window->DC.CursorPos;\n\twindow->DC.LayoutType = ImGuiLayoutType_Horizontal;\n\twindow->DC.IsSameLine = false;\n\tPushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max, true);\n\n\treturn true;\n}\n\nvoid ImGui::EndComboPreview()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiComboPreviewData* preview_data = &g.ComboPreviewData;\n\n\t// FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future\n\tImDrawList* draw_list = window->DrawList;\n\tif (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y)\n\t\tif (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command\n\t\t{\n\t\t\tdraw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect;\n\t\t\tdraw_list->_TryMergeDrawCmds();\n\t\t}\n\tPopClipRect();\n\twindow->DC.CursorPos = preview_data->BackupCursorPos;\n\twindow->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos);\n\twindow->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine;\n\twindow->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset;\n\twindow->DC.LayoutType = preview_data->BackupLayout;\n\twindow->DC.IsSameLine = false;\n\tpreview_data->PreviewRect = ImRect();\n}\n\n// Getter for the old Combo() API: const char*[]\nstatic bool Items_ArrayGetter(void* data, int idx, const char** out_text)\n{\n\tconst char* const* items = (const char* const*)data;\n\tif (out_text)\n\t\t*out_text = items[idx];\n\treturn true;\n}\n\n// Getter for the old Combo() API: \"item1\\0item2\\0item3\\0\"\nstatic bool Items_SingleStringGetter(void* data, int idx, const char** out_text)\n{\n\t// FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.\n\tconst char* items_separated_by_zeros = (const char*)data;\n\tint items_count = 0;\n\tconst char* p = items_separated_by_zeros;\n\twhile (*p)\n\t{\n\t\tif (idx == items_count)\n\t\t\tbreak;\n\t\tp += strlen(p) + 1;\n\t\titems_count++;\n\t}\n\tif (!*p)\n\t\treturn false;\n\tif (out_text)\n\t\t*out_text = p;\n\treturn true;\n}\n\n// Old API, prefer using BeginCombo() nowadays if you can.\nbool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Call the getter to obtain the preview string which is a parameter to BeginCombo()\n\tconst char* preview_value = NULL;\n\tif (*current_item >= 0 && *current_item < items_count)\n\t\titems_getter(data, *current_item, &preview_value);\n\n\t// The old Combo() API exposed \"popup_max_height_in_items\". The new more general BeginCombo() API doesn't have/need it, but we emulate it here.\n\tif (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))\n\t\tSetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));\n\n\tif (!BeginCombo(label, preview_value, ImGuiComboFlags_None))\n\t\treturn false;\n\n\t// Display items\n\t// FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed)\n\tbool value_changed = false;\n\tfor (int i = 0; i < items_count; i++)\n\t{\n\t\tPushID(i);\n\t\tconst bool item_selected = (i == *current_item);\n\t\tconst char* item_text;\n\t\tif (!items_getter(data, i, &item_text))\n\t\t\titem_text = \"*Unknown item*\";\n\t\tif (Selectable(item_text, item_selected) && *current_item != i)\n\t\t{\n\t\t\tvalue_changed = true;\n\t\t\t*current_item = i;\n\t\t}\n\t\tif (item_selected)\n\t\t\tSetItemDefaultFocus();\n\t\tPopID();\n\t}\n\n\tEndCombo();\n\n\tif (value_changed)\n\t\tMarkItemEdited(g.LastItemData.ID);\n\n\treturn value_changed;\n}\n\n// Combo box helper allowing to pass an array of strings.\nbool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items)\n{\n\tconst bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);\n\treturn value_changed;\n}\n\n// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items \"item1\\0item2\\0\"\nbool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)\n{\n\tint items_count = 0;\n\tconst char* p = items_separated_by_zeros;       // FIXME-OPT: Avoid computing this, or at least only when combo is open\n\twhile (*p)\n\t{\n\t\tp += strlen(p) + 1;\n\t\titems_count++;\n\t}\n\tbool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);\n\treturn value_changed;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Data Type and Data Formatting Helpers [Internal]\n//-------------------------------------------------------------------------\n// - DataTypeGetInfo()\n// - DataTypeFormatString()\n// - DataTypeApplyOp()\n// - DataTypeApplyOpFromText()\n// - DataTypeCompare()\n// - DataTypeClamp()\n// - GetMinimumStepAtDecimalPrecision\n// - RoundScalarWithFormat<>()\n//-------------------------------------------------------------------------\n\nstatic const ImGuiDataTypeInfo GDataTypeInfo[] =\n{\n\t{ sizeof(char),             \"S8\",   \"%d\",   \"%d\"    },  // ImGuiDataType_S8\n\t{ sizeof(unsigned char),    \"U8\",   \"%u\",   \"%u\"    },\n\t{ sizeof(short),            \"S16\",  \"%d\",   \"%d\"    },  // ImGuiDataType_S16\n\t{ sizeof(unsigned short),   \"U16\",  \"%u\",   \"%u\"    },\n\t{ sizeof(int),              \"S32\",  \"%d\",   \"%d\"    },  // ImGuiDataType_S32\n\t{ sizeof(unsigned int),     \"U32\",  \"%u\",   \"%u\"    },\n#ifdef _MSC_VER\n\t{ sizeof(ImS64),            \"S64\",  \"%I64d\",\"%I64d\" },  // ImGuiDataType_S64\n\t{ sizeof(ImU64),            \"U64\",  \"%I64u\",\"%I64u\" },\n#else\n\t{ sizeof(ImS64),            \"S64\",  \"%lld\", \"%lld\"  },  // ImGuiDataType_S64\n\t{ sizeof(ImU64),            \"U64\",  \"%llu\", \"%llu\"  },\n#endif\n\t{ sizeof(float),            \"float\", \"%.3f\",\"%f\"    },  // ImGuiDataType_Float (float are promoted to double in va_arg)\n\t{ sizeof(double),           \"double\",\"%f\",  \"%lf\"   },  // ImGuiDataType_Double\n};\nIM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT);\n\nconst ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type)\n{\n\tIM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);\n\treturn &GDataTypeInfo[data_type];\n}\n\nint ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format)\n{\n\t// Signedness doesn't matter when pushing integer arguments\n\tif (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImU32*)p_data);\n\tif (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImU64*)p_data);\n\tif (data_type == ImGuiDataType_Float)\n\t\treturn ImFormatString(buf, buf_size, format, *(const float*)p_data);\n\tif (data_type == ImGuiDataType_Double)\n\t\treturn ImFormatString(buf, buf_size, format, *(const double*)p_data);\n\tif (data_type == ImGuiDataType_S8)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImS8*)p_data);\n\tif (data_type == ImGuiDataType_U8)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImU8*)p_data);\n\tif (data_type == ImGuiDataType_S16)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImS16*)p_data);\n\tif (data_type == ImGuiDataType_U16)\n\t\treturn ImFormatString(buf, buf_size, format, *(const ImU16*)p_data);\n\tIM_ASSERT(0);\n\treturn 0;\n}\n\nvoid ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg1, const void* arg2)\n{\n\tIM_ASSERT(op == '+' || op == '-');\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S8:\n\t\tif (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); }\n\t\tif (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_U8:\n\t\tif (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); }\n\t\tif (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_S16:\n\t\tif (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); }\n\t\tif (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_U16:\n\t\tif (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); }\n\t\tif (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_S32:\n\t\tif (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); }\n\t\tif (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_U32:\n\t\tif (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); }\n\t\tif (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_S64:\n\t\tif (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); }\n\t\tif (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_U64:\n\t\tif (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); }\n\t\tif (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); }\n\t\treturn;\n\tcase ImGuiDataType_Float:\n\t\tif (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; }\n\t\tif (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; }\n\t\treturn;\n\tcase ImGuiDataType_Double:\n\t\tif (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; }\n\t\tif (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; }\n\t\treturn;\n\tcase ImGuiDataType_COUNT: break;\n\t}\n\tIM_ASSERT(0);\n}\n\n// User can input math operators (e.g. +100) to edit a numerical values.\n// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess..\nbool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format)\n{\n\twhile (ImCharIsBlankA(*buf))\n\t\tbuf++;\n\tif (!buf[0])\n\t\treturn false;\n\n\t// Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all.\n\tconst ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);\n\tImGuiDataTypeTempStorage data_backup;\n\tmemcpy(&data_backup, p_data, type_info->Size);\n\n\t// Sanitize format\n\t// - For float/double we have to ignore format with precision (e.g. \"%.2f\") because sscanf doesn't take them in, so force them into %f and %lf\n\t// - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %.\n\tchar format_sanitized[32];\n\tif (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)\n\t\tformat = type_info->ScanFmt;\n\telse\n\t\tformat = ImParseFormatSanitizeForScanning(format, format_sanitized, IM_ARRAYSIZE(format_sanitized));\n\n\t// Small types need a 32-bit buffer to receive the result from scanf()\n\tint v32 = 0;\n\tif (sscanf(buf, format, type_info->Size >= 4 ? p_data : &v32) < 1)\n\t\treturn false;\n\tif (type_info->Size < 4)\n\t{\n\t\tif (data_type == ImGuiDataType_S8)\n\t\t\t*(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX);\n\t\telse if (data_type == ImGuiDataType_U8)\n\t\t\t*(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX);\n\t\telse if (data_type == ImGuiDataType_S16)\n\t\t\t*(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX);\n\t\telse if (data_type == ImGuiDataType_U16)\n\t\t\t*(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX);\n\t\telse\n\t\t\tIM_ASSERT(0);\n\t}\n\n\treturn memcmp(&data_backup, p_data, type_info->Size) != 0;\n}\n\ntemplate<typename T>\nstatic int DataTypeCompareT(const T* lhs, const T* rhs)\n{\n\tif (*lhs < *rhs) return -1;\n\tif (*lhs > *rhs) return +1;\n\treturn 0;\n}\n\nint ImGui::DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2)\n{\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S8:     return DataTypeCompareT<ImS8  >((const ImS8*)arg_1, (const ImS8*)arg_2);\n\tcase ImGuiDataType_U8:     return DataTypeCompareT<ImU8  >((const ImU8*)arg_1, (const ImU8*)arg_2);\n\tcase ImGuiDataType_S16:    return DataTypeCompareT<ImS16 >((const ImS16*)arg_1, (const ImS16*)arg_2);\n\tcase ImGuiDataType_U16:    return DataTypeCompareT<ImU16 >((const ImU16*)arg_1, (const ImU16*)arg_2);\n\tcase ImGuiDataType_S32:    return DataTypeCompareT<ImS32 >((const ImS32*)arg_1, (const ImS32*)arg_2);\n\tcase ImGuiDataType_U32:    return DataTypeCompareT<ImU32 >((const ImU32*)arg_1, (const ImU32*)arg_2);\n\tcase ImGuiDataType_S64:    return DataTypeCompareT<ImS64 >((const ImS64*)arg_1, (const ImS64*)arg_2);\n\tcase ImGuiDataType_U64:    return DataTypeCompareT<ImU64 >((const ImU64*)arg_1, (const ImU64*)arg_2);\n\tcase ImGuiDataType_Float:  return DataTypeCompareT<float >((const float*)arg_1, (const float*)arg_2);\n\tcase ImGuiDataType_Double: return DataTypeCompareT<double>((const double*)arg_1, (const double*)arg_2);\n\tcase ImGuiDataType_COUNT:  break;\n\t}\n\tIM_ASSERT(0);\n\treturn 0;\n}\n\ntemplate<typename T>\nstatic bool DataTypeClampT(T* v, const T* v_min, const T* v_max)\n{\n\t// Clamp, both sides are optional, return true if modified\n\tif (v_min && *v < *v_min) { *v = *v_min; return true; }\n\tif (v_max && *v > *v_max) { *v = *v_max; return true; }\n\treturn false;\n}\n\nbool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max)\n{\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S8:     return DataTypeClampT<ImS8  >((ImS8*)p_data, (const ImS8*)p_min, (const ImS8*)p_max);\n\tcase ImGuiDataType_U8:     return DataTypeClampT<ImU8  >((ImU8*)p_data, (const ImU8*)p_min, (const ImU8*)p_max);\n\tcase ImGuiDataType_S16:    return DataTypeClampT<ImS16 >((ImS16*)p_data, (const ImS16*)p_min, (const ImS16*)p_max);\n\tcase ImGuiDataType_U16:    return DataTypeClampT<ImU16 >((ImU16*)p_data, (const ImU16*)p_min, (const ImU16*)p_max);\n\tcase ImGuiDataType_S32:    return DataTypeClampT<ImS32 >((ImS32*)p_data, (const ImS32*)p_min, (const ImS32*)p_max);\n\tcase ImGuiDataType_U32:    return DataTypeClampT<ImU32 >((ImU32*)p_data, (const ImU32*)p_min, (const ImU32*)p_max);\n\tcase ImGuiDataType_S64:    return DataTypeClampT<ImS64 >((ImS64*)p_data, (const ImS64*)p_min, (const ImS64*)p_max);\n\tcase ImGuiDataType_U64:    return DataTypeClampT<ImU64 >((ImU64*)p_data, (const ImU64*)p_min, (const ImU64*)p_max);\n\tcase ImGuiDataType_Float:  return DataTypeClampT<float >((float*)p_data, (const float*)p_min, (const float*)p_max);\n\tcase ImGuiDataType_Double: return DataTypeClampT<double>((double*)p_data, (const double*)p_min, (const double*)p_max);\n\tcase ImGuiDataType_COUNT:  break;\n\t}\n\tIM_ASSERT(0);\n\treturn false;\n}\n\nstatic float GetMinimumStepAtDecimalPrecision(int decimal_precision)\n{\n\tstatic const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };\n\tif (decimal_precision < 0)\n\t\treturn FLT_MIN;\n\treturn (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision);\n}\n\ntemplate<typename TYPE>\nTYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v)\n{\n\tIM_UNUSED(data_type);\n\tIM_ASSERT(data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double);\n\tconst char* fmt_start = ImParseFormatFindStart(format);\n\tif (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string\n\t\treturn v;\n\n\t// Sanitize format\n\tchar fmt_sanitized[32];\n\tImParseFormatSanitizeForPrinting(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized));\n\tfmt_start = fmt_sanitized;\n\n\t// Format value with our rounding, and read back\n\tchar v_str[64];\n\tImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v);\n\tconst char* p = v_str;\n\twhile (*p == ' ')\n\t\tp++;\n\tv = (TYPE)ImAtof(p);\n\n\treturn v;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc.\n//-------------------------------------------------------------------------\n// - DragBehaviorT<>() [Internal]\n// - DragBehavior() [Internal]\n// - DragScalar()\n// - DragScalarN()\n// - DragFloat()\n// - DragFloat2()\n// - DragFloat3()\n// - DragFloat4()\n// - DragFloatRange2()\n// - DragInt()\n// - DragInt2()\n// - DragInt3()\n// - DragInt4()\n// - DragIntRange2()\n//-------------------------------------------------------------------------\n\n// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls)\ntemplate<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>\nbool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;\n\tconst bool is_clamped = (v_min < v_max);\n\tconst bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;\n\tconst bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);\n\n\t// Default tweak speed\n\tif (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))\n\t\tv_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio);\n\n\t// Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings\n\tfloat adjust_delta = 0.0f;\n\tif (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR))\n\t{\n\t\tadjust_delta = g.IO.MouseDelta[axis];\n\t\tif (g.IO.KeyAlt)\n\t\t\tadjust_delta *= 1.0f / 100.0f;\n\t\tif (g.IO.KeyShift)\n\t\t\tadjust_delta *= 10.0f;\n\t}\n\telse if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)\n\t{\n\t\tconst int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0;\n\t\tconst bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);\n\t\tconst bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);\n\t\tconst float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f;\n\t\tadjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor;\n\t\tv_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));\n\t}\n\tadjust_delta *= v_speed;\n\n\t// For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter.\n\tif (axis == ImGuiAxis_Y)\n\t\tadjust_delta = -adjust_delta;\n\n\t// For logarithmic use our range is effectively 0..1 so scale the delta into that range\n\tif (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) // Epsilon to avoid /0\n\t\tadjust_delta /= (float)(v_max - v_min);\n\n\t// Clear current value on activation\n\t// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.\n\tbool is_just_activated = g.ActiveIdIsJustActivated;\n\tbool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));\n\tif (is_just_activated || is_already_past_limits_and_pushing_outward)\n\t{\n\t\tg.DragCurrentAccum = 0.0f;\n\t\tg.DragCurrentAccumDirty = false;\n\t}\n\telse if (adjust_delta != 0.0f)\n\t{\n\t\tg.DragCurrentAccum += adjust_delta;\n\t\tg.DragCurrentAccumDirty = true;\n\t}\n\n\tif (!g.DragCurrentAccumDirty)\n\t\treturn false;\n\n\tTYPE v_cur = *v;\n\tFLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f;\n\n\tfloat logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true\n\tconst float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense)\n\tif (is_logarithmic)\n\t{\n\t\t// When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound.\n\t\tconst int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1;\n\t\tlogarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision);\n\n\t\t// Convert to parametric space, apply delta, convert back\n\t\tfloat v_old_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\tfloat v_new_parametric = v_old_parametric + g.DragCurrentAccum;\n\t\tv_cur = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\tv_old_ref_for_accum_remainder = v_old_parametric;\n\t}\n\telse\n\t{\n\t\tv_cur += (SIGNEDTYPE)g.DragCurrentAccum;\n\t}\n\n\t// Round to user desired precision based on format string\n\tif (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))\n\t\tv_cur = RoundScalarWithFormatT<TYPE>(format, data_type, v_cur);\n\n\t// Preserve remainder after rounding has been applied. This also allow slow tweaking of values.\n\tg.DragCurrentAccumDirty = false;\n\tif (is_logarithmic)\n\t{\n\t\t// Convert to parametric space, apply delta, convert back\n\t\tfloat v_new_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\tg.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder);\n\t}\n\telse\n\t{\n\t\tg.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v);\n\t}\n\n\t// Lose zero sign for float/double\n\tif (v_cur == (TYPE)-0)\n\t\tv_cur = (TYPE)0;\n\n\t// Clamp values (+ handle overflow/wrap-around for integer types)\n\tif (*v != v_cur && is_clamped)\n\t{\n\t\tif (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))\n\t\t\tv_cur = v_min;\n\t\tif (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))\n\t\t\tv_cur = v_max;\n\t}\n\n\t// Apply result\n\tif (*v == v_cur)\n\t\treturn false;\n\t*v = v_cur;\n\treturn true;\n}\n\nbool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)\n{\n\t// Read imgui.cpp \"API BREAKING CHANGES\" section for 1.78 if you hit this assert.\n\tIM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && \"Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.\");\n\n\tImGuiContext& g = *GImGui;\n\tif (g.ActiveId == id)\n\t{\n\t\t// Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation.\n\t\tif (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0])\n\t\t\tClearActiveID();\n\t\telse if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)\n\t\t\tClearActiveID();\n\t}\n\tif (g.ActiveId != id)\n\t\treturn false;\n\tif ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))\n\t\treturn false;\n\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S8: { ImS32 v32 = (ImS32) * (ImS8*)p_v;  bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*)p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }\n\tcase ImGuiDataType_U8: { ImU32 v32 = (ImU32) * (ImU8*)p_v;  bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*)p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }\n\tcase ImGuiDataType_S16: { ImS32 v32 = (ImS32) * (ImS16*)p_v; bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }\n\tcase ImGuiDataType_U16: { ImU32 v32 = (ImU32) * (ImU16*)p_v; bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }\n\tcase ImGuiDataType_S32:    return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32*)p_min : IM_S32_MIN, p_max ? *(const ImS32*)p_max : IM_S32_MAX, format, flags);\n\tcase ImGuiDataType_U32:    return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32*)p_min : IM_U32_MIN, p_max ? *(const ImU32*)p_max : IM_U32_MAX, format, flags);\n\tcase ImGuiDataType_S64:    return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64*)p_min : IM_S64_MIN, p_max ? *(const ImS64*)p_max : IM_S64_MAX, format, flags);\n\tcase ImGuiDataType_U64:    return DragBehaviorT<ImU64, ImS64, double>(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64*)p_min : IM_U64_MIN, p_max ? *(const ImU64*)p_max : IM_U64_MAX, format, flags);\n\tcase ImGuiDataType_Float:  return DragBehaviorT<float, float, float >(data_type, (float*)p_v, v_speed, p_min ? *(const float*)p_min : -FLT_MAX, p_max ? *(const float*)p_max : FLT_MAX, format, flags);\n\tcase ImGuiDataType_Double: return DragBehaviorT<double, double, double>(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags);\n\tcase ImGuiDataType_COUNT:  break;\n\t}\n\tIM_ASSERT(0);\n\treturn false;\n}\n\n// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional.\n// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.\nbool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tconst float w = CalcItemWidth();\n\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));\n\tconst ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));\n\n\tconst bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))\n\t\treturn false;\n\n\t// Default format string when passing NULL\n\tif (format == NULL)\n\t\tformat = DataTypeGetInfo(data_type)->PrintFmt;\n\n\tconst bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);\n\tbool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);\n\tif (!temp_input_is_active)\n\t{\n\t\t// Tabbing or CTRL-clicking on Drag turns it into an InputText\n\t\tconst bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;\n\t\tconst bool clicked = hovered && IsMouseClicked(0, id);\n\t\tconst bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id));\n\t\tconst bool make_active = (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id);\n\t\tif (make_active && (clicked || double_clicked))\n\t\t\tSetKeyOwner(ImGuiKey_MouseLeft, id);\n\t\tif (make_active && temp_input_allowed)\n\t\t\tif (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput)))\n\t\t\t\ttemp_input_is_active = true;\n\n\t\t// (Optional) simple click (without moving) turns Drag into an InputText\n\t\tif (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active)\n\t\t\tif (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR))\n\t\t\t{\n\t\t\t\tg.NavActivateId = id;\n\t\t\t\tg.NavActivateFlags = ImGuiActivateFlags_PreferInput;\n\t\t\t\ttemp_input_is_active = true;\n\t\t\t}\n\n\t\tif (make_active && !temp_input_is_active)\n\t\t{\n\t\t\tSetActiveID(id, window);\n\t\t\tSetFocusID(id, window);\n\t\t\tFocusWindow(window);\n\t\t\tg.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);\n\t\t}\n\t}\n\n\tif (temp_input_is_active)\n\t{\n\t\t// Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set\n\t\tconst bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0);\n\t\treturn TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);\n\t}\n\n\t// Draw frame\n\tconst ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);\n\tRenderNavHighlight(frame_bb, id);\n\tRenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);\n\n\t// Drag behavior\n\tconst bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags);\n\tif (value_changed)\n\t\tMarkItemEdited(id);\n\n\t// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.\n\tchar value_buf[64];\n\tconst char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);\n\tif (g.LogEnabled)\n\t\tLogSetNextTextDecoration(\"{\", \"}\");\n\tRenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));\n\n\tif (label_size.x > 0.0f)\n\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));\n\treturn value_changed;\n}\n\nbool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tbool value_changed = false;\n\tBeginGroup();\n\tPushID(label);\n\tPushMultiItemsWidths(components, CalcItemWidth());\n\tsize_t type_size = GDataTypeInfo[data_type].Size;\n\tfor (int i = 0; i < components; i++)\n\t{\n\t\tPushID(i);\n\t\tif (i > 0)\n\t\t\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\t\tvalue_changed |= DragScalar(\"\", data_type, p_data, v_speed, p_min, p_max, format, flags);\n\t\tPopID();\n\t\tPopItemWidth();\n\t\tp_data = (void*)((char*)p_data + type_size);\n\t}\n\tPopID();\n\n\tconst char* label_end = FindRenderedTextEnd(label);\n\tif (label != label_end)\n\t{\n\t\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\t\tTextEx(label, label_end);\n\t}\n\n\tEndGroup();\n\treturn value_changed;\n}\n\nbool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags);\n}\n\n// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this.\nbool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tPushID(label);\n\tBeginGroup();\n\tPushMultiItemsWidths(2, CalcItemWidth());\n\n\tfloat min_min = (v_min >= v_max) ? -FLT_MAX : v_min;\n\tfloat min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);\n\tImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0);\n\tbool value_changed = DragScalar(\"##min\", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags);\n\tPopItemWidth();\n\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\n\tfloat max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);\n\tfloat max_max = (v_min >= v_max) ? FLT_MAX : v_max;\n\tImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0);\n\tvalue_changed |= DragScalar(\"##max\", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags);\n\tPopItemWidth();\n\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\n\tTextEx(label, FindRenderedTextEnd(label));\n\tEndGroup();\n\tPopID();\n\n\treturn value_changed;\n}\n\n// NB: v_speed is float to allow adjusting the drag speed with more precision\nbool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags);\n}\n\n// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this.\nbool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tPushID(label);\n\tBeginGroup();\n\tPushMultiItemsWidths(2, CalcItemWidth());\n\n\tint min_min = (v_min >= v_max) ? INT_MIN : v_min;\n\tint min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);\n\tImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0);\n\tbool value_changed = DragInt(\"##min\", v_current_min, v_speed, min_min, min_max, format, min_flags);\n\tPopItemWidth();\n\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\n\tint max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);\n\tint max_max = (v_min >= v_max) ? INT_MAX : v_max;\n\tImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0);\n\tvalue_changed |= DragInt(\"##max\", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags);\n\tPopItemWidth();\n\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\n\tTextEx(label, FindRenderedTextEnd(label));\n\tEndGroup();\n\tPopID();\n\n\treturn value_changed;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc.\n//-------------------------------------------------------------------------\n// - ScaleRatioFromValueT<> [Internal]\n// - ScaleValueFromRatioT<> [Internal]\n// - SliderBehaviorT<>() [Internal]\n// - SliderBehavior() [Internal]\n// - SliderScalar()\n// - SliderScalarN()\n// - SliderFloat()\n// - SliderFloat2()\n// - SliderFloat3()\n// - SliderFloat4()\n// - SliderAngle()\n// - SliderInt()\n// - SliderInt2()\n// - SliderInt3()\n// - SliderInt4()\n// - VSliderScalar()\n// - VSliderFloat()\n// - VSliderInt()\n//-------------------------------------------------------------------------\n\n// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT)\ntemplate<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>\nfloat ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)\n{\n\tif (v_min == v_max)\n\t\treturn 0.0f;\n\tIM_UNUSED(data_type);\n\n\tconst TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);\n\tif (is_logarithmic)\n\t{\n\t\tbool flipped = v_max < v_min;\n\n\t\tif (flipped) // Handle the case where the range is backwards\n\t\t\tImSwap(v_min, v_max);\n\n\t\t// Fudge min/max to avoid getting close to log(0)\n\t\tFLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;\n\t\tFLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;\n\n\t\t// Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon)\n\t\tif ((v_min == 0.0f) && (v_max < 0.0f))\n\t\t\tv_min_fudged = -logarithmic_zero_epsilon;\n\t\telse if ((v_max == 0.0f) && (v_min < 0.0f))\n\t\t\tv_max_fudged = -logarithmic_zero_epsilon;\n\n\t\tfloat result;\n\t\tif (v_clamped <= v_min_fudged)\n\t\t\tresult = 0.0f; // Workaround for values that are in-range but below our fudge\n\t\telse if (v_clamped >= v_max_fudged)\n\t\t\tresult = 1.0f; // Workaround for values that are in-range but above our fudge\n\t\telse if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions\n\t\t{\n\t\t\tfloat zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space.  There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine)\n\t\t\tfloat zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;\n\t\t\tfloat zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;\n\t\t\tif (v == 0.0f)\n\t\t\t\tresult = zero_point_center; // Special case for exactly zero\n\t\t\telse if (v < 0.0f)\n\t\t\t\tresult = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L;\n\t\t\telse\n\t\t\t\tresult = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R));\n\t\t}\n\t\telse if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider\n\t\t\tresult = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged));\n\t\telse\n\t\t\tresult = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged));\n\n\t\treturn flipped ? (1.0f - result) : result;\n\t}\n\telse\n\t{\n\t\t// Linear slider\n\t\treturn (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));\n\t}\n}\n\n// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)\ntemplate<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>\nTYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)\n{\n\t// We special-case the extents because otherwise our logarithmic fudging can lead to \"mathematically correct\"\n\t// but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler.\n\tif (t <= 0.0f || v_min == v_max)\n\t\treturn v_min;\n\tif (t >= 1.0f)\n\t\treturn v_max;\n\n\tTYPE result = (TYPE)0;\n\tif (is_logarithmic)\n\t{\n\t\t// Fudge min/max to avoid getting silly results close to zero\n\t\tFLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;\n\t\tFLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;\n\n\t\tconst bool flipped = v_max < v_min; // Check if range is \"backwards\"\n\t\tif (flipped)\n\t\t\tImSwap(v_min_fudged, v_max_fudged);\n\n\t\t// Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon)\n\t\tif ((v_max == 0.0f) && (v_min < 0.0f))\n\t\t\tv_max_fudged = -logarithmic_zero_epsilon;\n\n\t\tfloat t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range\n\n\t\tif ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts\n\t\t{\n\t\t\tfloat zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space\n\t\t\tfloat zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;\n\t\t\tfloat zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;\n\t\t\tif (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R)\n\t\t\t\tresult = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise)\n\t\t\telse if (t_with_flip < zero_point_center)\n\t\t\t\tresult = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L))));\n\t\t\telse\n\t\t\t\tresult = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R))));\n\t\t}\n\t\telse if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider\n\t\t\tresult = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip)));\n\t\telse\n\t\t\tresult = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));\n\t}\n\telse\n\t{\n\t\t// Linear slider\n\t\tconst bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);\n\t\tif (is_floating_point)\n\t\t{\n\t\t\tresult = ImLerp(v_min, v_max, t);\n\t\t}\n\t\telse if (t < 1.0)\n\t\t{\n\t\t\t// - For integer values we want the clicking position to match the grab box so we round above\n\t\t\t//   This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property..\n\t\t\t// - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64\n\t\t\t//   range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits.\n\t\t\tFLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t;\n\t\t\tresult = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5)));\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// FIXME: Try to move more of the code into shared SliderBehavior()\ntemplate<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>\nbool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\n\tconst ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;\n\tconst bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;\n\tconst bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);\n\tconst float v_range_f = (float)(v_min < v_max ? v_max - v_min : v_min - v_max); // We don't need high precision for what we do with it.\n\n\t// Calculate bounds\n\tconst float grab_padding = 2.0f; // FIXME: Should be part of style.\n\tconst float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;\n\tfloat grab_sz = style.GrabMinSize;\n\tif (!is_floating_point && v_range_f >= 0.0f)                         // v_range_f < 0 may happen on integer overflows\n\t\tgrab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit\n\tgrab_sz = ImMin(grab_sz, slider_sz);\n\tconst float slider_usable_sz = slider_sz - grab_sz;\n\tconst float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;\n\tconst float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f;\n\n\tfloat logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true\n\tfloat zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true\n\tif (is_logarithmic)\n\t{\n\t\t// When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound.\n\t\tconst int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1;\n\t\tlogarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision);\n\t\tzero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f);\n\t}\n\n\t// Process interacting with the slider\n\tbool value_changed = false;\n\tif (g.ActiveId == id)\n\t{\n\t\tbool set_new_value = false;\n\t\tfloat clicked_t = 0.0f;\n\t\tif (g.ActiveIdSource == ImGuiInputSource_Mouse)\n\t\t{\n\t\t\tif (!g.IO.MouseDown[0])\n\t\t\t{\n\t\t\t\tClearActiveID();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst float mouse_abs_pos = g.IO.MousePos[axis];\n\t\t\t\tif (g.ActiveIdIsJustActivated)\n\t\t\t\t{\n\t\t\t\t\tfloat grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\t\t\t\tif (axis == ImGuiAxis_Y)\n\t\t\t\t\t\tgrab_t = 1.0f - grab_t;\n\t\t\t\t\tconst float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);\n\t\t\t\t\tconst bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here.\n\t\t\t\t\tg.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f;\n\t\t\t\t}\n\t\t\t\tif (slider_usable_sz > 0.0f)\n\t\t\t\t\tclicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz);\n\t\t\t\tif (axis == ImGuiAxis_Y)\n\t\t\t\t\tclicked_t = 1.0f - clicked_t;\n\t\t\t\tset_new_value = true;\n\t\t\t}\n\t\t}\n\t\telse if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)\n\t\t{\n\t\t\tif (g.ActiveIdIsJustActivated)\n\t\t\t{\n\t\t\t\tg.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation\n\t\t\t\tg.SliderCurrentAccumDirty = false;\n\t\t\t}\n\n\t\t\tfloat input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis);\n\t\t\tif (input_delta != 0.0f)\n\t\t\t{\n\t\t\t\tconst bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);\n\t\t\t\tconst bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);\n\t\t\t\tconst int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0;\n\t\t\t\tif (decimal_precision > 0)\n\t\t\t\t{\n\t\t\t\t\tinput_delta /= 100.0f;    // Gamepad/keyboard tweak speeds in % of slider bounds\n\t\t\t\t\tif (tweak_slow)\n\t\t\t\t\t\tinput_delta /= 10.0f;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow)\n\t\t\t\t\t\tinput_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Gamepad/keyboard tweak speeds in integer steps\n\t\t\t\t\telse\n\t\t\t\t\t\tinput_delta /= 100.0f;\n\t\t\t\t}\n\t\t\t\tif (tweak_fast)\n\t\t\t\t\tinput_delta *= 10.0f;\n\n\t\t\t\tg.SliderCurrentAccum += input_delta;\n\t\t\t\tg.SliderCurrentAccumDirty = true;\n\t\t\t}\n\n\t\t\tfloat delta = g.SliderCurrentAccum;\n\t\t\tif (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)\n\t\t\t{\n\t\t\t\tClearActiveID();\n\t\t\t}\n\t\t\telse if (g.SliderCurrentAccumDirty)\n\t\t\t{\n\t\t\t\tclicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\n\t\t\t\tif ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits\n\t\t\t\t{\n\t\t\t\t\tset_new_value = false;\n\t\t\t\t\tg.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tset_new_value = true;\n\t\t\t\t\tfloat old_clicked_t = clicked_t;\n\t\t\t\t\tclicked_t = ImSaturate(clicked_t + delta);\n\n\t\t\t\t\t// Calculate what our \"new\" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator\n\t\t\t\t\tTYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\t\t\t\tif (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))\n\t\t\t\t\t\tv_new = RoundScalarWithFormatT<TYPE>(format, data_type, v_new);\n\t\t\t\t\tfloat new_clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\n\t\t\t\t\tif (delta > 0)\n\t\t\t\t\t\tg.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta);\n\t\t\t\t\telse\n\t\t\t\t\t\tg.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta);\n\t\t\t\t}\n\n\t\t\t\tg.SliderCurrentAccumDirty = false;\n\t\t\t}\n\t\t}\n\n\t\tif (set_new_value)\n\t\t\tif ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))\n\t\t\t\tset_new_value = false;\n\n\t\tif (set_new_value)\n\t\t{\n\t\t\tTYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\n\t\t\t// Round to user desired precision based on format string\n\t\t\tif (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))\n\t\t\t\tv_new = RoundScalarWithFormatT<TYPE>(format, data_type, v_new);\n\n\t\t\t// Apply result\n\t\t\tif (*v != v_new)\n\t\t\t{\n\t\t\t\t*v = v_new;\n\t\t\t\tvalue_changed = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (slider_sz < 1.0f)\n\t{\n\t\t*out_grab_bb = ImRect(bb.Min, bb.Min);\n\t}\n\telse\n\t{\n\t\t// Output grab position so it can be displayed by the caller\n\t\tfloat grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);\n\t\tif (axis == ImGuiAxis_Y)\n\t\t\tgrab_t = 1.0f - grab_t;\n\t\tconst float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);\n\t\tif (axis == ImGuiAxis_X)\n\t\t\t*out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding);\n\t\telse\n\t\t\t*out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f);\n\t}\n\n\treturn value_changed;\n}\n\n// For 32-bit and larger types, slider bounds are limited to half the natural type range.\n// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok.\n// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders.\nbool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)\n{\n\t// Read imgui.cpp \"API BREAKING CHANGES\" section for 1.78 if you hit this assert.\n\tIM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && \"Invalid ImGuiSliderFlags flag!  Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.\");\n\n\tswitch (data_type)\n\t{\n\tcase ImGuiDataType_S8: { ImS32 v32 = (ImS32) * (ImS8*)p_v;  bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32;  return r; }\n\tcase ImGuiDataType_U8: { ImU32 v32 = (ImU32) * (ImU8*)p_v;  bool r = SliderBehaviorT<ImU32, ImS32, float>(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32;  return r; }\n\tcase ImGuiDataType_S16: { ImS32 v32 = (ImS32) * (ImS16*)p_v; bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }\n\tcase ImGuiDataType_U16: { ImU32 v32 = (ImU32) * (ImU16*)p_v; bool r = SliderBehaviorT<ImU32, ImS32, float>(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }\n\tcase ImGuiDataType_S32:\n\t\tIM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2);\n\t\treturn SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_U32:\n\t\tIM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2);\n\t\treturn SliderBehaviorT<ImU32, ImS32, float >(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_S64:\n\t\tIM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2);\n\t\treturn SliderBehaviorT<ImS64, ImS64, double>(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_U64:\n\t\tIM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2);\n\t\treturn SliderBehaviorT<ImU64, ImS64, double>(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_Float:\n\t\tIM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f);\n\t\treturn SliderBehaviorT<float, float, float >(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_Double:\n\t\tIM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f);\n\t\treturn SliderBehaviorT<double, double, double>(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb);\n\tcase ImGuiDataType_COUNT: break;\n\t}\n\tIM_ASSERT(0);\n\treturn false;\n}\n\n// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required.\n// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.\nbool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tconst float w = CalcItemWidth();\n\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));\n\tconst ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));\n\n\tconst bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))\n\t\treturn false;\n\n\t// Default format string when passing NULL\n\tif (format == NULL)\n\t\tformat = DataTypeGetInfo(data_type)->PrintFmt;\n\n\tconst bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);\n\tbool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);\n\tif (!temp_input_is_active)\n\t{\n\t\t// Tabbing or CTRL-clicking on Slider turns it into an input box\n\t\tconst bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;\n\t\tconst bool clicked = hovered && IsMouseClicked(0, id);\n\t\tconst bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id);\n\t\tif (make_active && clicked)\n\t\t\tSetKeyOwner(ImGuiKey_MouseLeft, id);\n\t\tif (make_active && temp_input_allowed)\n\t\t\tif (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput)))\n\t\t\t\ttemp_input_is_active = true;\n\n\t\tif (make_active && !temp_input_is_active)\n\t\t{\n\t\t\tSetActiveID(id, window);\n\t\t\tSetFocusID(id, window);\n\t\t\tFocusWindow(window);\n\t\t\tg.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);\n\t\t}\n\t}\n\n\tif (temp_input_is_active)\n\t{\n\t\t// Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set\n\t\tconst bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0;\n\t\treturn TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);\n\t}\n\n\t// Draw frame\n\tconst ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);\n\tRenderNavHighlight(frame_bb, id);\n\tRenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);\n\n\t// Slider behavior\n\tImRect grab_bb;\n\tconst bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb);\n\tif (value_changed)\n\t\tMarkItemEdited(id);\n\n\t// Render grab\n\tif (grab_bb.Max.x > grab_bb.Min.x)\n\t\twindow->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);\n\n\t// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.\n\tchar value_buf[64];\n\tconst char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);\n\tif (g.LogEnabled)\n\t\tLogSetNextTextDecoration(\"{\", \"}\");\n\tRenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));\n\n\tif (label_size.x > 0.0f)\n\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));\n\treturn value_changed;\n}\n\n// Add multiple sliders on 1 line for compact edition of multiple components\nbool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tbool value_changed = false;\n\tBeginGroup();\n\tPushID(label);\n\tPushMultiItemsWidths(components, CalcItemWidth());\n\tsize_t type_size = GDataTypeInfo[data_type].Size;\n\tfor (int i = 0; i < components; i++)\n\t{\n\t\tPushID(i);\n\t\tif (i > 0)\n\t\t\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\t\tvalue_changed |= SliderScalar(\"\", data_type, v, v_min, v_max, format, flags);\n\t\tPopID();\n\t\tPopItemWidth();\n\t\tv = (void*)((char*)v + type_size);\n\t}\n\tPopID();\n\n\tconst char* label_end = FindRenderedTextEnd(label);\n\tif (label != label_end)\n\t{\n\t\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\t\tTextEx(label, label_end);\n\t}\n\n\tEndGroup();\n\treturn value_changed;\n}\n\nbool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags)\n{\n\tif (format == NULL)\n\t\tformat = \"%.0f deg\";\n\tfloat v_deg = (*v_rad) * 360.0f / (2 * IM_PI);\n\tbool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags);\n\t*v_rad = v_deg * (2 * IM_PI) / 360.0f;\n\treturn value_changed;\n}\n\nbool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tconst ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));\n\n\tItemSize(bb, style.FramePadding.y);\n\tif (!ItemAdd(frame_bb, id))\n\t\treturn false;\n\n\t// Default format string when passing NULL\n\tif (format == NULL)\n\t\tformat = DataTypeGetInfo(data_type)->PrintFmt;\n\n\tconst bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);\n\tconst bool clicked = hovered && IsMouseClicked(0, id);\n\tif (clicked || g.NavActivateId == id)\n\t{\n\t\tif (clicked)\n\t\t\tSetKeyOwner(ImGuiKey_MouseLeft, id);\n\t\tSetActiveID(id, window);\n\t\tSetFocusID(id, window);\n\t\tFocusWindow(window);\n\t\tg.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);\n\t}\n\n\t// Draw frame\n\tconst ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);\n\tRenderNavHighlight(frame_bb, id);\n\tRenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);\n\n\t// Slider behavior\n\tImRect grab_bb;\n\tconst bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb);\n\tif (value_changed)\n\t\tMarkItemEdited(id);\n\n\t// Render grab\n\tif (grab_bb.Max.y > grab_bb.Min.y)\n\t\twindow->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);\n\n\t// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.\n\t// For the vertical slider we allow centered text to overlap the frame padding\n\tchar value_buf[64];\n\tconst char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);\n\tRenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));\n\tif (label_size.x > 0.0f)\n\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);\n\n\treturn value_changed;\n}\n\nbool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);\n}\n\nbool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)\n{\n\treturn VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc.\n//-------------------------------------------------------------------------\n// - ImParseFormatFindStart() [Internal]\n// - ImParseFormatFindEnd() [Internal]\n// - ImParseFormatTrimDecorations() [Internal]\n// - ImParseFormatSanitizeForPrinting() [Internal]\n// - ImParseFormatSanitizeForScanning() [Internal]\n// - ImParseFormatPrecision() [Internal]\n// - TempInputTextScalar() [Internal]\n// - InputScalar()\n// - InputScalarN()\n// - InputFloat()\n// - InputFloat2()\n// - InputFloat3()\n// - InputFloat4()\n// - InputInt()\n// - InputInt2()\n// - InputInt3()\n// - InputInt4()\n// - InputDouble()\n//-------------------------------------------------------------------------\n\n// We don't use strchr() because our strings are usually very short and often start with '%'\nconst char* ImParseFormatFindStart(const char* fmt)\n{\n\twhile (char c = fmt[0])\n\t{\n\t\tif (c == '%' && fmt[1] != '%')\n\t\t\treturn fmt;\n\t\telse if (c == '%')\n\t\t\tfmt++;\n\t\tfmt++;\n\t}\n\treturn fmt;\n}\n\nconst char* ImParseFormatFindEnd(const char* fmt)\n{\n\t// Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format.\n\tif (fmt[0] != '%')\n\t\treturn fmt;\n\tconst unsigned int ignored_uppercase_mask = (1 << ('I' - 'A')) | (1 << ('L' - 'A'));\n\tconst unsigned int ignored_lowercase_mask = (1 << ('h' - 'a')) | (1 << ('j' - 'a')) | (1 << ('l' - 'a')) | (1 << ('t' - 'a')) | (1 << ('w' - 'a')) | (1 << ('z' - 'a'));\n\tfor (char c; (c = *fmt) != 0; fmt++)\n\t{\n\t\tif (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0)\n\t\t\treturn fmt + 1;\n\t\tif (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0)\n\t\t\treturn fmt + 1;\n\t}\n\treturn fmt;\n}\n\n// Extract the format out of a format string with leading or trailing decorations\n//  fmt = \"blah blah\"  -> return \"\"\n//  fmt = \"%.3f\"       -> return fmt\n//  fmt = \"hello %.3f\" -> return fmt + 6\n//  fmt = \"%.3f hello\" -> return buf written with \"%.3f\"\nconst char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size)\n{\n\tconst char* fmt_start = ImParseFormatFindStart(fmt);\n\tif (fmt_start[0] != '%')\n\t\treturn \"\";\n\tconst char* fmt_end = ImParseFormatFindEnd(fmt_start);\n\tif (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data.\n\t\treturn fmt_start;\n\tImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size));\n\treturn buf;\n}\n\n// Sanitize format\n// - Zero terminate so extra characters after format (e.g. \"%f123\") don't confuse atof/atoi\n// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi.\nvoid ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size)\n{\n\tconst char* fmt_end = ImParseFormatFindEnd(fmt_in);\n\tIM_UNUSED(fmt_out_size);\n\tIM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you!\n\twhile (fmt_in < fmt_end)\n\t{\n\t\tchar c = *fmt_in++;\n\t\tif (c != '\\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.\n\t\t\t*(fmt_out++) = c;\n\t}\n\t*fmt_out = 0; // Zero-terminate\n}\n\n// - For scanning we need to remove all width and precision fields and flags \"%+3.7f\" -> \"%f\". BUT don't strip types like \"%I64d\" which includes digits. ! \"%07I64d\" -> \"%I64d\"\nconst char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size)\n{\n\tconst char* fmt_end = ImParseFormatFindEnd(fmt_in);\n\tconst char* fmt_out_begin = fmt_out;\n\tIM_UNUSED(fmt_out_size);\n\tIM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you!\n\tbool has_type = false;\n\twhile (fmt_in < fmt_end)\n\t{\n\t\tchar c = *fmt_in++;\n\t\tif (!has_type && ((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '#'))\n\t\t\tcontinue;\n\t\thas_type |= ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); // Stop skipping digits\n\t\tif (c != '\\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.\n\t\t\t*(fmt_out++) = c;\n\t}\n\t*fmt_out = 0; // Zero-terminate\n\treturn fmt_out_begin;\n}\n\ntemplate<typename TYPE>\nstatic const char* ImAtoi(const char* src, TYPE* output)\n{\n\tint negative = 0;\n\tif (*src == '-') { negative = 1; src++; }\n\tif (*src == '+') { src++; }\n\tTYPE v = 0;\n\twhile (*src >= '0' && *src <= '9')\n\t\tv = (v * 10) + (*src++ - '0');\n\t*output = negative ? -v : v;\n\treturn src;\n}\n\n// Parse display precision back from the display format string\n// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed.\nint ImParseFormatPrecision(const char* fmt, int default_precision)\n{\n\tfmt = ImParseFormatFindStart(fmt);\n\tif (fmt[0] != '%')\n\t\treturn default_precision;\n\tfmt++;\n\twhile (*fmt >= '0' && *fmt <= '9')\n\t\tfmt++;\n\tint precision = INT_MAX;\n\tif (*fmt == '.')\n\t{\n\t\tfmt = ImAtoi<int>(fmt + 1, &precision);\n\t\tif (precision < 0 || precision > 99)\n\t\t\tprecision = default_precision;\n\t}\n\tif (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation\n\t\tprecision = -1;\n\tif ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX)\n\t\tprecision = -1;\n\treturn (precision == INT_MAX) ? default_precision : precision;\n}\n\n// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets)\n// FIXME: Facilitate using this in variety of other situations.\nbool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags)\n{\n\t// On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id.\n\t// We clear ActiveID on the first frame to allow the InputText() taking it back.\n\tImGuiContext& g = *GImGui;\n\tconst bool init = (g.TempInputId != id);\n\tif (init)\n\t\tClearActiveID();\n\n\tg.CurrentWindow->DC.CursorPos = bb.Min;\n\tbool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem);\n\tif (init)\n\t{\n\t\t// First frame we started displaying the InputText widget, we expect it to take the active id.\n\t\tIM_ASSERT(g.ActiveId == id);\n\t\tg.TempInputId = g.ActiveId;\n\t}\n\treturn value_changed;\n}\n\nstatic inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(ImGuiDataType data_type, const char* format)\n{\n\tif (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)\n\t\treturn ImGuiInputTextFlags_CharsScientific;\n\tconst char format_last_char = format[0] ? format[strlen(format) - 1] : 0;\n\treturn (format_last_char == 'x' || format_last_char == 'X') ? ImGuiInputTextFlags_CharsHexadecimal : ImGuiInputTextFlags_CharsDecimal;\n}\n\n// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the ImGuiSliderFlags_AlwaysClamp flag is set!\n// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility.\n// However this may not be ideal for all uses, as some user code may break on out of bound values.\nbool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max)\n{\n\t// FIXME: May need to clarify display behavior if format doesn't contain %.\n\t// \"%d\" -> \"%d\" / \"There are %d items\" -> \"%d\" / \"items\" -> \"%d\" (fallback). Also see #6405\n\tconst ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);\n\tchar fmt_buf[32];\n\tchar data_buf[32];\n\tformat = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));\n\tif (format[0] == 0)\n\t\tformat = type_info->PrintFmt;\n\tDataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format);\n\tImStrTrimBlanks(data_buf);\n\n\tImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited;\n\tflags |= InputScalar_DefaultCharsFilter(data_type, format);\n\n\tbool value_changed = false;\n\tif (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags))\n\t{\n\t\t// Backup old value\n\t\tsize_t data_type_size = type_info->Size;\n\t\tImGuiDataTypeTempStorage data_backup;\n\t\tmemcpy(&data_backup, p_data, data_type_size);\n\n\t\t// Apply new value (or operations) then clamp\n\t\tDataTypeApplyFromText(data_buf, data_type, p_data, format);\n\t\tif (p_clamp_min || p_clamp_max)\n\t\t{\n\t\t\tif (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0)\n\t\t\t\tImSwap(p_clamp_min, p_clamp_max);\n\t\t\tDataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);\n\t\t}\n\n\t\t// Only mark as edited if new value is different\n\t\tvalue_changed = memcmp(&data_backup, p_data, data_type_size) != 0;\n\t\tif (value_changed)\n\t\t\tMarkItemEdited(id);\n\t}\n\treturn value_changed;\n}\n\n// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional.\n// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.\nbool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiStyle& style = g.Style;\n\n\tif (format == NULL)\n\t\tformat = DataTypeGetInfo(data_type)->PrintFmt;\n\n\tchar buf[64];\n\tDataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);\n\n\t// Testing ActiveId as a minor optimization as filtering is not needed until active\n\tif (g.ActiveId == 0 && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)\n\t\tflags |= InputScalar_DefaultCharsFilter(data_type, format);\n\tflags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.\n\n\tbool value_changed = false;\n\tif (p_step == NULL)\n\t{\n\t\tif (InputText(label, buf, IM_ARRAYSIZE(buf), flags))\n\t\t\tvalue_changed = DataTypeApplyFromText(buf, data_type, p_data, format);\n\t}\n\telse\n\t{\n\t\tconst float button_size = GetFrameHeight();\n\n\t\tBeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()\n\t\tPushID(label);\n\t\tSetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));\n\t\tif (InputText(\"\", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + \"\" gives us the expected ID from outside point of view\n\t\t\tvalue_changed = DataTypeApplyFromText(buf, data_type, p_data, format);\n\t\tIMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);\n\n\t\t// Step buttons\n\t\tconst ImVec2 backup_frame_padding = style.FramePadding;\n\t\tstyle.FramePadding.x = style.FramePadding.y;\n\t\tImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups;\n\t\tif (flags & ImGuiInputTextFlags_ReadOnly)\n\t\t\tBeginDisabled();\n\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\tif (ButtonEx(\"-\", ImVec2(button_size, button_size), button_flags))\n\t\t{\n\t\t\tDataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);\n\t\t\tvalue_changed = true;\n\t\t}\n\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\tif (ButtonEx(\"+\", ImVec2(button_size, button_size), button_flags))\n\t\t{\n\t\t\tDataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);\n\t\t\tvalue_changed = true;\n\t\t}\n\t\tif (flags & ImGuiInputTextFlags_ReadOnly)\n\t\t\tEndDisabled();\n\n\t\tconst char* label_end = FindRenderedTextEnd(label);\n\t\tif (label != label_end)\n\t\t{\n\t\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\t\tTextEx(label, label_end);\n\t\t}\n\t\tstyle.FramePadding = backup_frame_padding;\n\n\t\tPopID();\n\t\tEndGroup();\n\t}\n\tif (value_changed)\n\t\tMarkItemEdited(g.LastItemData.ID);\n\n\treturn value_changed;\n}\n\nbool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tbool value_changed = false;\n\tBeginGroup();\n\tPushID(label);\n\tPushMultiItemsWidths(components, CalcItemWidth());\n\tsize_t type_size = GDataTypeInfo[data_type].Size;\n\tfor (int i = 0; i < components; i++)\n\t{\n\t\tPushID(i);\n\t\tif (i > 0)\n\t\t\tSameLine(0, g.Style.ItemInnerSpacing.x);\n\t\tvalue_changed |= InputScalar(\"\", data_type, p_data, p_step, p_step_fast, format, flags);\n\t\tPopID();\n\t\tPopItemWidth();\n\t\tp_data = (void*)((char*)p_data + type_size);\n\t}\n\tPopID();\n\n\tconst char* label_end = FindRenderedTextEnd(label);\n\tif (label != label_end)\n\t{\n\t\tSameLine(0.0f, g.Style.ItemInnerSpacing.x);\n\t\tTextEx(label, label_end);\n\t}\n\n\tEndGroup();\n\treturn value_changed;\n}\n\nbool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags)\n{\n\tflags |= ImGuiInputTextFlags_CharsScientific;\n\treturn InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags);\n}\n\nbool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags);\n}\n\nbool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags);\n}\n\nbool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags);\n}\n\nbool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags)\n{\n\t// Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.\n\tconst char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? \"%08X\" : \"%d\";\n\treturn InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags);\n}\n\nbool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, \"%d\", flags);\n}\n\nbool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, \"%d\", flags);\n}\n\nbool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags)\n{\n\treturn InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, \"%d\", flags);\n}\n\nbool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags)\n{\n\tflags |= ImGuiInputTextFlags_CharsScientific;\n\treturn InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint\n//-------------------------------------------------------------------------\n// - InputText()\n// - InputTextWithHint()\n// - InputTextMultiline()\n// - InputTextGetCharInfo() [Internal]\n// - InputTextReindexLines() [Internal]\n// - InputTextReindexLinesRange() [Internal]\n// - InputTextEx() [Internal]\n// - DebugNodeInputTextState() [Internal]\n//-------------------------------------------------------------------------\n\nbool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)\n{\n\tIM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()\n\treturn InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);\n}\n\nbool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)\n{\n\treturn InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);\n}\n\nbool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)\n{\n\tIM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or  InputTextEx() manually if you need multi-line + hint.\n\treturn InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);\n}\n\nstatic int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)\n{\n\tint line_count = 0;\n\tconst char* s = text_begin;\n\twhile (char c = *s++) // We are only matching for \\n so we can ignore UTF-8 decoding\n\t\tif (c == '\\n')\n\t\t\tline_count++;\n\ts--;\n\tif (s[0] != '\\n' && s[0] != '\\r')\n\t\tline_count++;\n\t*out_text_end = s;\n\treturn line_count;\n}\n\nstatic ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)\n{\n\tImGuiContext& g = *ctx;\n\tImFont* font = g.Font;\n\tconst float line_height = g.FontSize;\n\tconst float scale = line_height / font->FontSize;\n\n\tImVec2 text_size = ImVec2(0, 0);\n\tfloat line_width = 0.0f;\n\n\tconst ImWchar* s = text_begin;\n\twhile (s < text_end)\n\t{\n\t\tunsigned int c = (unsigned int)(*s++);\n\t\tif (c == '\\n')\n\t\t{\n\t\t\ttext_size.x = ImMax(text_size.x, line_width);\n\t\t\ttext_size.y += line_height;\n\t\t\tline_width = 0.0f;\n\t\t\tif (stop_on_new_line)\n\t\t\t\tbreak;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c == '\\r')\n\t\t\tcontinue;\n\n\t\tconst float char_width = font->GetCharAdvance((ImWchar)c) * scale;\n\t\tline_width += char_width;\n\t}\n\n\tif (text_size.x < line_width)\n\t\ttext_size.x = line_width;\n\n\tif (out_offset)\n\t\t*out_offset = ImVec2(line_width, text_size.y + line_height);  // offset allow for the possibility of sitting after a trailing \\n\n\n\tif (line_width > 0 || text_size.y == 0.0f)                        // whereas size.y will ignore the trailing \\n\n\t\ttext_size.y += line_height;\n\n\tif (remaining)\n\t\t*remaining = s;\n\n\treturn text_size;\n}\n\n// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)\nnamespace ImStb\n{\n\tstatic int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; }\n\tstatic ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; }\n\tstatic float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }\n\tstatic int     STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; }\n\tstatic ImWchar STB_TEXTEDIT_NEWLINE = '\\n';\n\tstatic void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)\n\t{\n\t\tconst ImWchar* text = obj->TextW.Data;\n\t\tconst ImWchar* text_remaining = NULL;\n\t\tconst ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);\n\t\tr->x0 = 0.0f;\n\t\tr->x1 = size.x;\n\t\tr->baseline_y_delta = size.y;\n\t\tr->ymin = 0.0f;\n\t\tr->ymax = size.y;\n\t\tr->num_chars = (int)(text_remaining - (text + line_start_idx));\n\t}\n\n\tstatic bool is_separator(unsigned int c)\n\t{\n\t\treturn c == ',' || c == ';' || c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || c == '|' || c == '\\n' || c == '\\r' || c == '.' || c == '!';\n\t}\n\n\tstatic int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)\n\t{\n\t\t// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators.\n\t\tif ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)\n\t\t\treturn 0;\n\n\t\tbool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]);\n\t\tbool prev_separ = is_separator(obj->TextW[idx - 1]);\n\t\tbool curr_white = ImCharIsBlankW(obj->TextW[idx]);\n\t\tbool curr_separ = is_separator(obj->TextW[idx]);\n\t\treturn ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);\n\t}\n\tstatic int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)\n\t{\n\t\tif ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)\n\t\t\treturn 0;\n\n\t\tbool prev_white = ImCharIsBlankW(obj->TextW[idx]);\n\t\tbool prev_separ = is_separator(obj->TextW[idx]);\n\t\tbool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]);\n\t\tbool curr_separ = is_separator(obj->TextW[idx - 1]);\n\t\treturn ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);\n\t}\n\tstatic int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }\n\tstatic int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }\n\tstatic int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }\n\tstatic int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }\n#define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL  // They need to be #define for stb_textedit.h\n#define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL\n\n\tstatic void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)\n\t{\n\t\tImWchar* dst = obj->TextW.Data + pos;\n\n\t\t// We maintain our buffer length in both UTF-8 and wchar formats\n\t\tobj->Edited = true;\n\t\tobj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);\n\t\tobj->CurLenW -= n;\n\n\t\t// Offset remaining text (FIXME-OPT: Use memmove)\n\t\tconst ImWchar* src = obj->TextW.Data + pos + n;\n\t\twhile (ImWchar c = *src++)\n\t\t\t*dst++ = c;\n\t\t*dst = '\\0';\n\t}\n\n\tstatic bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len)\n\t{\n\t\tconst bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0;\n\t\tconst int text_len = obj->CurLenW;\n\t\tIM_ASSERT(pos <= text_len);\n\n\t\tconst int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);\n\t\tif (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA))\n\t\t\treturn false;\n\n\t\t// Grow internal buffer if needed\n\t\tif (new_text_len + text_len + 1 > obj->TextW.Size)\n\t\t{\n\t\t\tif (!is_resizable)\n\t\t\t\treturn false;\n\t\t\tIM_ASSERT(text_len < obj->TextW.Size);\n\t\t\tobj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1);\n\t\t}\n\n\t\tImWchar* text = obj->TextW.Data;\n\t\tif (pos != text_len)\n\t\t\tmemmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));\n\t\tmemcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));\n\n\t\tobj->Edited = true;\n\t\tobj->CurLenW += new_text_len;\n\t\tobj->CurLenA += new_text_len_utf8;\n\t\tobj->TextW[obj->CurLenW] = '\\0';\n\n\t\treturn true;\n\t}\n\n\t// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)\n#define STB_TEXTEDIT_K_LEFT         0x200000 // keyboard input to move cursor left\n#define STB_TEXTEDIT_K_RIGHT        0x200001 // keyboard input to move cursor right\n#define STB_TEXTEDIT_K_UP           0x200002 // keyboard input to move cursor up\n#define STB_TEXTEDIT_K_DOWN         0x200003 // keyboard input to move cursor down\n#define STB_TEXTEDIT_K_LINESTART    0x200004 // keyboard input to move cursor to start of line\n#define STB_TEXTEDIT_K_LINEEND      0x200005 // keyboard input to move cursor to end of line\n#define STB_TEXTEDIT_K_TEXTSTART    0x200006 // keyboard input to move cursor to start of text\n#define STB_TEXTEDIT_K_TEXTEND      0x200007 // keyboard input to move cursor to end of text\n#define STB_TEXTEDIT_K_DELETE       0x200008 // keyboard input to delete selection or character under cursor\n#define STB_TEXTEDIT_K_BACKSPACE    0x200009 // keyboard input to delete selection or character left of cursor\n#define STB_TEXTEDIT_K_UNDO         0x20000A // keyboard input to perform undo\n#define STB_TEXTEDIT_K_REDO         0x20000B // keyboard input to perform redo\n#define STB_TEXTEDIT_K_WORDLEFT     0x20000C // keyboard input to move cursor left one word\n#define STB_TEXTEDIT_K_WORDRIGHT    0x20000D // keyboard input to move cursor right one word\n#define STB_TEXTEDIT_K_PGUP         0x20000E // keyboard input to move cursor up a page\n#define STB_TEXTEDIT_K_PGDOWN       0x20000F // keyboard input to move cursor down a page\n#define STB_TEXTEDIT_K_SHIFT        0x400000\n\n#define STB_TEXTEDIT_IMPLEMENTATION\n#define STB_TEXTEDIT_memmove memmove\n#include \"imstb_textedit.h\"\n\n// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling\n// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?)\n\tstatic void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len)\n\t{\n\t\tstb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len);\n\t\tImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW);\n\t\tstate->cursor = state->select_start = state->select_end = 0;\n\t\tif (text_len <= 0)\n\t\t\treturn;\n\t\tif (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len))\n\t\t{\n\t\t\tstate->cursor = state->select_start = state->select_end = text_len;\n\t\t\tstate->has_preferred_x = 0;\n\t\t\treturn;\n\t\t}\n\t\tIM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace()\n\t}\n} // namespace ImStb\n\nvoid ImGuiInputTextState::OnKeyPressed(int key)\n{\n\tstb_textedit_key(this, &Stb, key);\n\tCursorFollow = true;\n\tCursorAnimReset();\n}\n\nImGuiInputTextCallbackData::ImGuiInputTextCallbackData()\n{\n\tmemset(this, 0, sizeof(*this));\n}\n\n// Public API to manipulate UTF-8 text\n// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)\n// FIXME: The existence of this rarely exercised code path is a bit of a nuisance.\nvoid ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)\n{\n\tIM_ASSERT(pos + bytes_count <= BufTextLen);\n\tchar* dst = Buf + pos;\n\tconst char* src = Buf + pos + bytes_count;\n\twhile (char c = *src++)\n\t\t*dst++ = c;\n\t*dst = '\\0';\n\n\tif (CursorPos >= pos + bytes_count)\n\t\tCursorPos -= bytes_count;\n\telse if (CursorPos >= pos)\n\t\tCursorPos = pos;\n\tSelectionStart = SelectionEnd = CursorPos;\n\tBufDirty = true;\n\tBufTextLen -= bytes_count;\n}\n\nvoid ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)\n{\n\t// Accept null ranges\n\tif (new_text == new_text_end)\n\t\treturn;\n\n\tconst bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;\n\tconst int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);\n\tif (new_text_len + BufTextLen >= BufSize)\n\t{\n\t\tif (!is_resizable)\n\t\t\treturn;\n\n\t\t// Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!)\n\t\tImGuiContext& g = *Ctx;\n\t\tImGuiInputTextState* edit_state = &g.InputTextState;\n\t\tIM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID);\n\t\tIM_ASSERT(Buf == edit_state->TextA.Data);\n\t\tint new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1;\n\t\tedit_state->TextA.reserve(new_buf_size + 1);\n\t\tBuf = edit_state->TextA.Data;\n\t\tBufSize = edit_state->BufCapacityA = new_buf_size;\n\t}\n\n\tif (BufTextLen != pos)\n\t\tmemmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));\n\tmemcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));\n\tBuf[BufTextLen + new_text_len] = '\\0';\n\n\tif (CursorPos >= pos)\n\t\tCursorPos += new_text_len;\n\tSelectionStart = SelectionEnd = CursorPos;\n\tBufDirty = true;\n\tBufTextLen += new_text_len;\n}\n\n// Return false to discard a character.\nstatic bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source)\n{\n\tIM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard);\n\tunsigned int c = *p_char;\n\n\t// Filter non-printable (NB: isprint is unreliable! see #2467)\n\tbool apply_named_filters = true;\n\tif (c < 0x20)\n\t{\n\t\tbool pass = false;\n\t\tpass |= (c == '\\n' && (flags & ImGuiInputTextFlags_Multiline)); // Note that an Enter KEY will emit \\r and be ignored (we poll for KEY in InputText() code)\n\t\tpass |= (c == '\\t' && (flags & ImGuiInputTextFlags_AllowTabInput));\n\t\tif (!pass)\n\t\t\treturn false;\n\t\tapply_named_filters = false; // Override named filters below so newline and tabs can still be inserted.\n\t}\n\n\tif (input_source != ImGuiInputSource_Clipboard)\n\t{\n\t\t// We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817)\n\t\tif (c == 127)\n\t\t\treturn false;\n\n\t\t// Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME)\n\t\tif (c >= 0xE000 && c <= 0xF8FF)\n\t\t\treturn false;\n\t}\n\n\t// Filter Unicode ranges we are not handling in this build\n\tif (c > IM_UNICODE_CODEPOINT_MAX)\n\t\treturn false;\n\n\t// Generic named filters\n\tif (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)))\n\t{\n\t\t// The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, \"de_DE.UTF-8\");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'.\n\t\t// The standard mandate that programs starts in the \"C\" locale where the decimal point is '.'.\n\t\t// We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point.\n\t\t// Change the default decimal_point with:\n\t\t//   ImGui::GetIO()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point;\n\t\t// Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions.\n\t\tImGuiContext& g = *ctx;\n\t\tconst unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint;\n\t\tif (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific))\n\t\t\tif (c == '.' || c == ',')\n\t\t\t\tc = c_decimal_point;\n\n\t\t// Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block)\n\t\t// While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may\n\t\t// scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font.\n\t\tif (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal))\n\t\t\tif (c >= 0xFF01 && c <= 0xFF5E)\n\t\t\t\tc = c - 0xFF01 + 0x21;\n\n\t\t// Allow 0-9 . - + * /\n\t\tif (flags & ImGuiInputTextFlags_CharsDecimal)\n\t\t\tif (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/'))\n\t\t\t\treturn false;\n\n\t\t// Allow 0-9 . - + * / e E\n\t\tif (flags & ImGuiInputTextFlags_CharsScientific)\n\t\t\tif (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E'))\n\t\t\t\treturn false;\n\n\t\t// Allow 0-9 a-F A-F\n\t\tif (flags & ImGuiInputTextFlags_CharsHexadecimal)\n\t\t\tif (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))\n\t\t\t\treturn false;\n\n\t\t// Turn a-z into A-Z\n\t\tif (flags & ImGuiInputTextFlags_CharsUppercase)\n\t\t\tif (c >= 'a' && c <= 'z')\n\t\t\t\tc += (unsigned int)('A' - 'a');\n\n\t\tif (flags & ImGuiInputTextFlags_CharsNoBlank)\n\t\t\tif (ImCharIsBlankW(c))\n\t\t\t\treturn false;\n\n\t\t*p_char = c;\n\t}\n\n\t// Custom callback filter\n\tif (flags & ImGuiInputTextFlags_CallbackCharFilter)\n\t{\n\t\tImGuiContext& g = *GImGui;\n\t\tImGuiInputTextCallbackData callback_data;\n\t\tcallback_data.Ctx = &g;\n\t\tcallback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;\n\t\tcallback_data.EventChar = (ImWchar)c;\n\t\tcallback_data.Flags = flags;\n\t\tcallback_data.UserData = user_data;\n\t\tif (callback(&callback_data) != 0)\n\t\t\treturn false;\n\t\t*p_char = callback_data.EventChar;\n\t\tif (!callback_data.EventChar)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Find the shortest single replacement we can make to get the new text from the old text.\n// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end.\n// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly.\nstatic void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a)\n{\n\tImGuiContext& g = *GImGui;\n\tconst ImWchar* old_buf = state->TextW.Data;\n\tconst int old_length = state->CurLenW;\n\tconst int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a);\n\tg.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar));\n\tImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data;\n\tImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a);\n\n\tconst int shorter_length = ImMin(old_length, new_length);\n\tint first_diff;\n\tfor (first_diff = 0; first_diff < shorter_length; first_diff++)\n\t\tif (old_buf[first_diff] != new_buf[first_diff])\n\t\t\tbreak;\n\tif (first_diff == old_length && first_diff == new_length)\n\t\treturn;\n\n\tint old_last_diff = old_length - 1;\n\tint new_last_diff = new_length - 1;\n\tfor (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--)\n\t\tif (old_buf[old_last_diff] != new_buf[new_last_diff])\n\t\t\tbreak;\n\n\tconst int insert_len = new_last_diff - first_diff + 1;\n\tconst int delete_len = old_last_diff - first_diff + 1;\n\tif (insert_len > 0 || delete_len > 0)\n\t\tif (STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len))\n\t\t\tfor (int i = 0; i < delete_len; i++)\n\t\t\t\tp[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i);\n}\n\n// As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables)\n// we need some form of hook to reapply data back to user buffer on deactivation frame. (#4714)\n// It would be more desirable that we discourage users from taking advantage of the \"user not retaining data\" trick,\n// but that more likely be attractive when we do have _NoLiveEdit flag available.\nvoid ImGui::InputTextDeactivateHook(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiInputTextState* state = &g.InputTextState;\n\tif (id == 0 || state->ID != id)\n\t\treturn;\n\tg.InputTextDeactivatedState.ID = state->ID;\n\tif (state->Flags & ImGuiInputTextFlags_ReadOnly)\n\t{\n\t\tg.InputTextDeactivatedState.TextA.resize(0); // In theory this data won't be used, but clear to be neat.\n\t}\n\telse\n\t{\n\t\tIM_ASSERT(state->TextA.Data != 0);\n\t\tg.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1);\n\t\tmemcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1);\n\t}\n}\n\n// Edit a string of text\n// - buf_size account for the zero-terminator, so a buf_size of 6 can hold \"Hello\" but not \"Hello!\".\n//   This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match\n//   Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator.\n// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect.\n// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h\n// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are\n//  doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188)\nbool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tIM_ASSERT(buf != NULL && buf_size >= 0);\n\tIM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline)));        // Can't use both together (they both use up/down keys)\n\tIM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)\n\n\tImGuiContext& g = *GImGui;\n\tImGuiIO& io = g.IO;\n\tconst ImGuiStyle& style = g.Style;\n\n\tconst bool RENDER_SELECTION_WHEN_INACTIVE = false;\n\tconst bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;\n\tconst bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0;\n\tconst bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;\n\tconst bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;\n\tconst bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0;\n\tif (is_resizable)\n\t\tIM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!\n\n\tif (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar)\n\t\tBeginGroup();\n\tconst ImGuiID id = window->GetID(label);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line\n\tconst ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);\n\n\tconst ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);\n\tconst ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size);\n\n\tImGuiWindow* draw_window = window;\n\tImVec2 inner_size = frame_size;\n\tImGuiItemStatusFlags item_status_flags = 0;\n\tImGuiLastItemData item_data_backup;\n\tif (is_multiline)\n\t{\n\t\tImVec2 backup_pos = window->DC.CursorPos;\n\t\tItemSize(total_bb, style.FramePadding.y);\n\t\tif (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))\n\t\t{\n\t\t\tEndGroup();\n\t\t\treturn false;\n\t\t}\n\t\titem_status_flags = g.LastItemData.StatusFlags;\n\t\titem_data_backup = g.LastItemData;\n\t\twindow->DC.CursorPos = backup_pos;\n\n\t\t// We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.\n\t\t// FIXME-NAV: Pressing NavActivate will trigger general child activation right before triggering our own below. Harmless but bizarre.\n\t\tPushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);\n\t\tPushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);\n\t\tPushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);\n\t\tPushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges\n\t\tbool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove);\n\t\tPopStyleVar(3);\n\t\tPopStyleColor();\n\t\tif (!child_visible)\n\t\t{\n\t\t\tEndChild();\n\t\t\tEndGroup();\n\t\t\treturn false;\n\t\t}\n\t\tdraw_window = g.CurrentWindow; // Child window\n\t\tdraw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can \"enter\" into it.\n\t\tdraw_window->DC.CursorPos += style.FramePadding;\n\t\tinner_size.x -= draw_window->ScrollbarSizes.x;\n\t}\n\telse\n\t{\n\t\t// Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd)\n\t\tItemSize(total_bb, style.FramePadding.y);\n\t\tif (!(flags & ImGuiInputTextFlags_MergedItem))\n\t\t\tif (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))\n\t\t\t\treturn false;\n\t\titem_status_flags = g.LastItemData.StatusFlags;\n\t}\n\tconst bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);\n\tif (hovered)\n\t\tg.MouseCursor = ImGuiMouseCursor_TextInput;\n\n\t// We are only allowed to access the state if we are already the active widget.\n\tImGuiInputTextState* state = GetInputTextState(id);\n\n\tconst bool input_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;\n\tconst bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard)));\n\n\tconst bool user_clicked = hovered && io.MouseClicked[0];\n\tconst bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);\n\tconst bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);\n\tbool clear_active_id = false;\n\tbool select_all = false;\n\n\tfloat scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;\n\n\tconst bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state.\n\tconst bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing);\n\tconst bool init_state = (init_make_active || user_scroll_active);\n\tif ((init_state && g.ActiveId != id) || init_changed_specs)\n\t{\n\t\t// Access state even if we don't own it yet.\n\t\tstate = &g.InputTextState;\n\t\tstate->CursorAnimReset();\n\n\t\t// Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714)\n\t\tInputTextDeactivateHook(state->ID);\n\n\t\t// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)\n\t\t// From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)\n\t\tconst int buf_len = (int)strlen(buf);\n\t\tstate->InitialTextA.resize(buf_len + 1);    // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.\n\t\tmemcpy(state->InitialTextA.Data, buf, buf_len + 1);\n\n\t\t// Preserve cursor position and undo/redo stack if we come back to same widget\n\t\t// FIXME: Since we reworked this on 2022/06, may want to differenciate recycle_cursor vs recycle_undostate?\n\t\tbool recycle_state = (state->ID == id && !init_changed_specs);\n\t\tif (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0)))\n\t\t\trecycle_state = false;\n\n\t\t// Start edition\n\t\tconst char* buf_end = NULL;\n\t\tstate->ID = id;\n\t\tstate->TextW.resize(buf_size + 1);          // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.\n\t\tstate->TextA.resize(0);\n\t\tstate->TextAIsValid = false;                // TextA is not valid yet (we will display buf until then)\n\t\tstate->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);\n\t\tstate->CurLenA = (int)(buf_end - buf);      // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.\n\n\t\tif (recycle_state)\n\t\t{\n\t\t\t// Recycle existing cursor/selection/undo stack but clamp position\n\t\t\t// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.\n\t\t\tstate->CursorClamp();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstate->ScrollX = 0.0f;\n\t\t\tstb_textedit_initialize_state(&state->Stb, !is_multiline);\n\t\t}\n\n\t\tif (!is_multiline)\n\t\t{\n\t\t\tif (flags & ImGuiInputTextFlags_AutoSelectAll)\n\t\t\t\tselect_all = true;\n\t\t\tif (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState)))\n\t\t\t\tselect_all = true;\n\t\t\tif (input_requested_by_tabbing || (user_clicked && io.KeyCtrl))\n\t\t\t\tselect_all = true;\n\t\t}\n\n\t\tif (flags & ImGuiInputTextFlags_AlwaysOverwrite)\n\t\t\tstate->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863)\n\t}\n\n\tconst bool is_osx = io.ConfigMacOSXBehaviors;\n\tif (g.ActiveId != id && init_make_active)\n\t{\n\t\tIM_ASSERT(state && state->ID == id);\n\t\tSetActiveID(id, window);\n\t\tSetFocusID(id, window);\n\t\tFocusWindow(window);\n\t}\n\tif (g.ActiveId == id)\n\t{\n\t\t// Declare some inputs, the other are registered and polled via Shortcut() routing system.\n\t\tif (user_clicked)\n\t\t\tSetKeyOwner(ImGuiKey_MouseLeft, id);\n\t\tg.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);\n\t\tif (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))\n\t\t\tg.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);\n\t\tSetKeyOwner(ImGuiKey_Home, id);\n\t\tSetKeyOwner(ImGuiKey_End, id);\n\t\tif (is_multiline)\n\t\t{\n\t\t\tSetKeyOwner(ImGuiKey_PageUp, id);\n\t\t\tSetKeyOwner(ImGuiKey_PageDown, id);\n\t\t}\n\t\tif (is_osx)\n\t\t\tSetKeyOwner(ImGuiMod_Alt, id);\n\t\tif (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \\t character.\n\t\t\tSetShortcutRouting(ImGuiKey_Tab, id);\n\t}\n\n\t// We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function)\n\tif (g.ActiveId == id && state == NULL)\n\t\tClearActiveID();\n\n\t// Release focus when we click outside\n\tif (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560\n\t\tclear_active_id = true;\n\n\t// Lock the decision of whether we are going to take the path displaying the cursor or selection\n\tbool render_cursor = (g.ActiveId == id) || (state && user_scroll_active);\n\tbool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);\n\tbool value_changed = false;\n\tbool validated = false;\n\n\t// When read-only we always use the live data passed to the function\n\t// FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :(\n\tif (is_readonly && state != NULL && (render_cursor || render_selection))\n\t{\n\t\tconst char* buf_end = NULL;\n\t\tstate->TextW.resize(buf_size + 1);\n\t\tstate->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end);\n\t\tstate->CurLenA = (int)(buf_end - buf);\n\t\tstate->CursorClamp();\n\t\trender_selection &= state->HasSelection();\n\t}\n\n\t// Select the buffer to render.\n\tconst bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid;\n\tconst bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);\n\n\t// Password pushes a temporary font with only a fallback glyph\n\tif (is_password && !is_displaying_hint)\n\t{\n\t\tconst ImFontGlyph* glyph = g.Font->FindGlyph('*');\n\t\tImFont* password_font = &g.InputTextPasswordFont;\n\t\tpassword_font->FontSize = g.Font->FontSize;\n\t\tpassword_font->Scale = g.Font->Scale;\n\t\tpassword_font->Ascent = g.Font->Ascent;\n\t\tpassword_font->Descent = g.Font->Descent;\n\t\tpassword_font->ContainerAtlas = g.Font->ContainerAtlas;\n\t\tpassword_font->FallbackGlyph = glyph;\n\t\tpassword_font->FallbackAdvanceX = glyph->AdvanceX;\n\t\tIM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());\n\t\tPushFont(password_font);\n\t}\n\n\t// Process mouse inputs and character inputs\n\tint backup_current_text_length = 0;\n\tif (g.ActiveId == id)\n\t{\n\t\tIM_ASSERT(state != NULL);\n\t\tbackup_current_text_length = state->CurLenA;\n\t\tstate->Edited = false;\n\t\tstate->BufCapacityA = buf_size;\n\t\tstate->Flags = flags;\n\n\t\t// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.\n\t\t// Down the line we should have a cleaner library-wide concept of Selected vs Active.\n\t\tg.ActiveIdAllowOverlap = !io.MouseDown[0];\n\n\t\t// Edit in progress\n\t\tconst float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;\n\t\tconst float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f));\n\n\t\tif (select_all)\n\t\t{\n\t\t\tstate->SelectAll();\n\t\t\tstate->SelectedAllMouseLock = true;\n\t\t}\n\t\telse if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift)\n\t\t{\n\t\t\tstb_textedit_click(state, &state->Stb, mouse_x, mouse_y);\n\t\t\tconst int multiclick_count = (io.MouseClickedCount[0] - 2);\n\t\t\tif ((multiclick_count % 2) == 0)\n\t\t\t{\n\t\t\t\t// Double-click: Select word\n\t\t\t\t// We always use the \"Mac\" word advance for double-click select vs CTRL+Right which use the platform dependent variant:\n\t\t\t\t// FIXME: There are likely many ways to improve this behavior, but there's no \"right\" behavior (depends on use-case, software, OS)\n\t\t\t\tconst bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\\n';\n\t\t\t\tif (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol)\n\t\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);\n\t\t\t\t//state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);\n\t\t\t\tif (!STB_TEXT_HAS_SELECTION(&state->Stb))\n\t\t\t\t\tImStb::stb_textedit_prep_selection_at_cursor(&state->Stb);\n\t\t\t\tstate->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor);\n\t\t\t\tstate->Stb.select_end = state->Stb.cursor;\n\t\t\t\tImStb::stb_textedit_clamp(state, &state->Stb);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Triple-click: Select line\n\t\t\t\tconst bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\\n';\n\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_LINESTART);\n\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT);\n\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT);\n\t\t\t\tif (!is_eol && is_multiline)\n\t\t\t\t{\n\t\t\t\t\tImSwap(state->Stb.select_start, state->Stb.select_end);\n\t\t\t\t\tstate->Stb.cursor = state->Stb.select_end;\n\t\t\t\t}\n\t\t\t\tstate->CursorFollow = false;\n\t\t\t}\n\t\t\tstate->CursorAnimReset();\n\t\t}\n\t\telse if (io.MouseClicked[0] && !state->SelectedAllMouseLock)\n\t\t{\n\t\t\tif (hovered)\n\t\t\t{\n\t\t\t\tif (io.KeyShift)\n\t\t\t\t\tstb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);\n\t\t\t\telse\n\t\t\t\t\tstb_textedit_click(state, &state->Stb, mouse_x, mouse_y);\n\t\t\t\tstate->CursorAnimReset();\n\t\t\t}\n\t\t}\n\t\telse if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))\n\t\t{\n\t\t\tstb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);\n\t\t\tstate->CursorAnimReset();\n\t\t\tstate->CursorFollow = true;\n\t\t}\n\t\tif (state->SelectedAllMouseLock && !io.MouseDown[0])\n\t\t\tstate->SelectedAllMouseLock = false;\n\n\t\t// We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336)\n\t\t// (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes)\n\t\tif ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly)\n\t\t{\n\t\t\tunsigned int c = '\\t'; // Insert TAB\n\t\t\tif (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))\n\t\t\t\tstate->OnKeyPressed((int)c);\n\t\t}\n\n\t\t// Process regular text input (before we check for Return because using some IME will effectively send a Return?)\n\t\t// We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.\n\t\tconst bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);\n\t\tif (io.InputQueueCharacters.Size > 0)\n\t\t{\n\t\t\tif (!ignore_char_inputs && !is_readonly && !input_requested_by_nav)\n\t\t\t\tfor (int n = 0; n < io.InputQueueCharacters.Size; n++)\n\t\t\t\t{\n\t\t\t\t\t// Insert character if they pass filtering\n\t\t\t\t\tunsigned int c = (unsigned int)io.InputQueueCharacters[n];\n\t\t\t\t\tif (c == '\\t') // Skip Tab, see above.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))\n\t\t\t\t\t\tstate->OnKeyPressed((int)c);\n\t\t\t\t}\n\n\t\t\t// Consume characters\n\t\t\tio.InputQueueCharacters.resize(0);\n\t\t}\n\t}\n\n\t// Process other shortcuts/key-presses\n\tbool revert_edit = false;\n\tif (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)\n\t{\n\t\tIM_ASSERT(state != NULL);\n\n\t\tconst int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1);\n\t\tstate->Stb.row_count_per_page = row_count_per_page;\n\n\t\tconst int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);\n\t\tconst bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl;                     // OS X style: Text editing cursor movement using Alt instead of Ctrl\n\t\tconst bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt;  // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End\n\n\t\t// Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText)\n\t\t// Otherwise we could simply assume that we own the keys as we are active.\n\t\tconst ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;\n\t\tconst bool is_cut = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, id, f_repeat)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());\n\t\tconst bool is_copy = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, id)) && !is_password && (!is_multiline || state->HasSelection());\n\t\tconst bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, id, f_repeat)) && !is_readonly;\n\t\tconst bool is_undo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z, id, f_repeat)) && !is_readonly && is_undoable;\n\t\tconst bool is_redo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y, id, f_repeat) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z, id, f_repeat))) && !is_readonly && is_undoable;\n\t\tconst bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A, id);\n\n\t\t// We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.\n\t\tconst bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;\n\t\tconst bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true);\n\t\tconst bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));\n\t\tconst bool is_cancel = Shortcut(ImGuiKey_Escape, id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, id, f_repeat));\n\n\t\t// FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of.\n\t\tif (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; }\n\t\telse if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; }\n\t\telse if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }\n\t\telse if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut)\n\t\t{\n\t\t\tif (!state->HasSelection())\n\t\t\t{\n\t\t\t\t// OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace)\n\t\t\t\tif (is_wordmove_key_down)\n\t\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);\n\t\t\t}\n\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask);\n\t\t}\n\t\telse if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly)\n\t\t{\n\t\t\tif (!state->HasSelection())\n\t\t\t{\n\t\t\t\tif (is_wordmove_key_down)\n\t\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT);\n\t\t\t\telse if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl)\n\t\t\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT);\n\t\t\t}\n\t\t\tstate->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);\n\t\t}\n\t\telse if (is_enter_pressed || is_gamepad_validate)\n\t\t{\n\t\t\t// Determine if we turn Enter into a \\n character\n\t\t\tbool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;\n\t\t\tif (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))\n\t\t\t{\n\t\t\t\tvalidated = true;\n\t\t\t\tif (io.ConfigInputTextEnterKeepActive && !is_multiline)\n\t\t\t\t\tstate->SelectAll(); // No need to scroll\n\t\t\t\telse\n\t\t\t\t\tclear_active_id = true;\n\t\t\t}\n\t\t\telse if (!is_readonly)\n\t\t\t{\n\t\t\t\tunsigned int c = '\\n'; // Insert new line\n\t\t\t\tif (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))\n\t\t\t\t\tstate->OnKeyPressed((int)c);\n\t\t\t}\n\t\t}\n\t\telse if (is_cancel)\n\t\t{\n\t\t\tif (flags & ImGuiInputTextFlags_EscapeClearsAll)\n\t\t\t{\n\t\t\t\tif (buf[0] != 0)\n\t\t\t\t{\n\t\t\t\t\trevert_edit = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\trender_cursor = render_selection = false;\n\t\t\t\t\tclear_active_id = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tclear_active_id = revert_edit = true;\n\t\t\t\trender_cursor = render_selection = false;\n\t\t\t}\n\t\t}\n\t\telse if (is_undo || is_redo)\n\t\t{\n\t\t\tstate->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);\n\t\t\tstate->ClearSelection();\n\t\t}\n\t\telse if (is_select_all)\n\t\t{\n\t\t\tstate->SelectAll();\n\t\t\tstate->CursorFollow = true;\n\t\t}\n\t\telse if (is_cut || is_copy)\n\t\t{\n\t\t\t// Cut, Copy\n\t\t\tif (io.SetClipboardTextFn)\n\t\t\t{\n\t\t\t\tconst int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;\n\t\t\t\tconst int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;\n\t\t\t\tconst int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;\n\t\t\t\tchar* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));\n\t\t\t\tImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);\n\t\t\t\tSetClipboardText(clipboard_data);\n\t\t\t\tMemFree(clipboard_data);\n\t\t\t}\n\t\t\tif (is_cut)\n\t\t\t{\n\t\t\t\tif (!state->HasSelection())\n\t\t\t\t\tstate->SelectAll();\n\t\t\t\tstate->CursorFollow = true;\n\t\t\t\tstb_textedit_cut(state, &state->Stb);\n\t\t\t}\n\t\t}\n\t\telse if (is_paste)\n\t\t{\n\t\t\tif (const char* clipboard = GetClipboardText())\n\t\t\t{\n\t\t\t\t// Filter pasted buffer\n\t\t\t\tconst int clipboard_len = (int)strlen(clipboard);\n\t\t\t\tImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar));\n\t\t\t\tint clipboard_filtered_len = 0;\n\t\t\t\tfor (const char* s = clipboard; *s != 0; )\n\t\t\t\t{\n\t\t\t\t\tunsigned int c;\n\t\t\t\t\ts += ImTextCharFromUtf8(&c, s, NULL);\n\t\t\t\t\tif (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tclipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;\n\t\t\t\t}\n\t\t\t\tclipboard_filtered[clipboard_filtered_len] = 0;\n\t\t\t\tif (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation\n\t\t\t\t{\n\t\t\t\t\tstb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);\n\t\t\t\t\tstate->CursorFollow = true;\n\t\t\t\t}\n\t\t\t\tMemFree(clipboard_filtered);\n\t\t\t}\n\t\t}\n\n\t\t// Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame.\n\t\trender_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);\n\t}\n\n\t// Process callbacks and apply result back to user's buffer.\n\tconst char* apply_new_text = NULL;\n\tint apply_new_text_length = 0;\n\tif (g.ActiveId == id)\n\t{\n\t\tIM_ASSERT(state != NULL);\n\t\tif (revert_edit && !is_readonly)\n\t\t{\n\t\t\tif (flags & ImGuiInputTextFlags_EscapeClearsAll)\n\t\t\t{\n\t\t\t\t// Clear input\n\t\t\t\tIM_ASSERT(buf[0] != 0);\n\t\t\t\tapply_new_text = \"\";\n\t\t\t\tapply_new_text_length = 0;\n\t\t\t\tvalue_changed = true;\n\t\t\t\tSTB_TEXTEDIT_CHARTYPE empty_string;\n\t\t\t\tstb_textedit_replace(state, &state->Stb, &empty_string, 0);\n\t\t\t}\n\t\t\telse if (strcmp(buf, state->InitialTextA.Data) != 0)\n\t\t\t{\n\t\t\t\t// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.\n\t\t\t\t// Push records into the undo stack so we can CTRL+Z the revert operation itself\n\t\t\t\tapply_new_text = state->InitialTextA.Data;\n\t\t\t\tapply_new_text_length = state->InitialTextA.Size - 1;\n\t\t\t\tvalue_changed = true;\n\t\t\t\tImVector<ImWchar> w_text;\n\t\t\t\tif (apply_new_text_length > 0)\n\t\t\t\t{\n\t\t\t\t\tw_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1);\n\t\t\t\t\tImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length);\n\t\t\t\t}\n\t\t\t\tstb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0);\n\t\t\t}\n\t\t}\n\n\t\t// Apply ASCII value\n\t\tif (!is_readonly)\n\t\t{\n\t\t\tstate->TextAIsValid = true;\n\t\t\tstate->TextA.resize(state->TextW.Size * 4 + 1);\n\t\t\tImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL);\n\t\t}\n\n\t\t// When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer\n\t\t// before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.\n\t\t// If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail.\n\t\t// This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage\n\t\t// (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object\n\t\t// unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize).\n\t\tconst bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);\n\t\tif (apply_edit_back_to_user_buffer)\n\t\t{\n\t\t\t// Apply new value immediately - copy modified buffer back\n\t\t\t// Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer\n\t\t\t// FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.\n\t\t\t// FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.\n\n\t\t\t// User callback\n\t\t\tif ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)\n\t\t\t{\n\t\t\t\tIM_ASSERT(callback != NULL);\n\n\t\t\t\t// The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.\n\t\t\t\tImGuiInputTextFlags event_flag = 0;\n\t\t\t\tImGuiKey event_key = ImGuiKey_None;\n\t\t\t\tif ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, id))\n\t\t\t\t{\n\t\t\t\t\tevent_flag = ImGuiInputTextFlags_CallbackCompletion;\n\t\t\t\t\tevent_key = ImGuiKey_Tab;\n\t\t\t\t}\n\t\t\t\telse if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow))\n\t\t\t\t{\n\t\t\t\t\tevent_flag = ImGuiInputTextFlags_CallbackHistory;\n\t\t\t\t\tevent_key = ImGuiKey_UpArrow;\n\t\t\t\t}\n\t\t\t\telse if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow))\n\t\t\t\t{\n\t\t\t\t\tevent_flag = ImGuiInputTextFlags_CallbackHistory;\n\t\t\t\t\tevent_key = ImGuiKey_DownArrow;\n\t\t\t\t}\n\t\t\t\telse if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited)\n\t\t\t\t{\n\t\t\t\t\tevent_flag = ImGuiInputTextFlags_CallbackEdit;\n\t\t\t\t}\n\t\t\t\telse if (flags & ImGuiInputTextFlags_CallbackAlways)\n\t\t\t\t{\n\t\t\t\t\tevent_flag = ImGuiInputTextFlags_CallbackAlways;\n\t\t\t\t}\n\n\t\t\t\tif (event_flag)\n\t\t\t\t{\n\t\t\t\t\tImGuiInputTextCallbackData callback_data;\n\t\t\t\t\tcallback_data.Ctx = &g;\n\t\t\t\t\tcallback_data.EventFlag = event_flag;\n\t\t\t\t\tcallback_data.Flags = flags;\n\t\t\t\t\tcallback_data.UserData = callback_user_data;\n\n\t\t\t\t\tchar* callback_buf = is_readonly ? buf : state->TextA.Data;\n\t\t\t\t\tcallback_data.EventKey = event_key;\n\t\t\t\t\tcallback_data.Buf = callback_buf;\n\t\t\t\t\tcallback_data.BufTextLen = state->CurLenA;\n\t\t\t\t\tcallback_data.BufSize = state->BufCapacityA;\n\t\t\t\t\tcallback_data.BufDirty = false;\n\n\t\t\t\t\t// We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)\n\t\t\t\t\tImWchar* text = state->TextW.Data;\n\t\t\t\t\tconst int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor);\n\t\t\t\t\tconst int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start);\n\t\t\t\t\tconst int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end);\n\n\t\t\t\t\t// Call user code\n\t\t\t\t\tcallback(&callback_data);\n\n\t\t\t\t\t// Read back what user may have modified\n\t\t\t\t\tcallback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback\n\t\t\t\t\tIM_ASSERT(callback_data.Buf == callback_buf);         // Invalid to modify those fields\n\t\t\t\t\tIM_ASSERT(callback_data.BufSize == state->BufCapacityA);\n\t\t\t\t\tIM_ASSERT(callback_data.Flags == flags);\n\t\t\t\t\tconst bool buf_dirty = callback_data.BufDirty;\n\t\t\t\t\tif (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; }\n\t\t\t\t\tif (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }\n\t\t\t\t\tif (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }\n\t\t\t\t\tif (buf_dirty)\n\t\t\t\t\t{\n\t\t\t\t\t\tIM_ASSERT((flags & ImGuiInputTextFlags_ReadOnly) == 0);\n\t\t\t\t\t\tIM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!\n\t\t\t\t\t\tInputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?\n\t\t\t\t\t\tif (callback_data.BufTextLen > backup_current_text_length && is_resizable)\n\t\t\t\t\t\t\tstate->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize\n\t\t\t\t\t\tstate->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);\n\t\t\t\t\t\tstate->CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()\n\t\t\t\t\t\tstate->CursorAnimReset();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Will copy result string if modified\n\t\t\tif (!is_readonly && strcmp(state->TextA.Data, buf) != 0)\n\t\t\t{\n\t\t\t\tapply_new_text = state->TextA.Data;\n\t\t\t\tapply_new_text_length = state->CurLenA;\n\t\t\t\tvalue_changed = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details)\n\tif (g.InputTextDeactivatedState.ID == id)\n\t{\n\t\tif (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0)\n\t\t{\n\t\t\tapply_new_text = g.InputTextDeactivatedState.TextA.Data;\n\t\t\tapply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1;\n\t\t\tvalue_changed = true;\n\t\t\t//IMGUI_DEBUG_LOG(\"InputText(): apply Deactivated data for 0x%08X: \\\"%.*s\\\".\\n\", id, apply_new_text_length, apply_new_text);\n\t\t}\n\t\tg.InputTextDeactivatedState.ID = 0;\n\t}\n\n\t// Copy result to user buffer. This can currently only happen when (g.ActiveId == id)\n\tif (apply_new_text != NULL)\n\t{\n\t\t// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size\n\t\t// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used\n\t\t// without any storage on user's side.\n\t\tIM_ASSERT(apply_new_text_length >= 0);\n\t\tif (is_resizable)\n\t\t{\n\t\t\tImGuiInputTextCallbackData callback_data;\n\t\t\tcallback_data.Ctx = &g;\n\t\t\tcallback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;\n\t\t\tcallback_data.Flags = flags;\n\t\t\tcallback_data.Buf = buf;\n\t\t\tcallback_data.BufTextLen = apply_new_text_length;\n\t\t\tcallback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1);\n\t\t\tcallback_data.UserData = callback_user_data;\n\t\t\tcallback(&callback_data);\n\t\t\tbuf = callback_data.Buf;\n\t\t\tbuf_size = callback_data.BufSize;\n\t\t\tapply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1);\n\t\t\tIM_ASSERT(apply_new_text_length <= buf_size);\n\t\t}\n\t\t//IMGUI_DEBUG_PRINT(\"InputText(\\\"%s\\\"): apply_new_text length %d\\n\", label, apply_new_text_length);\n\n\t\t// If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.\n\t\tImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));\n\t}\n\n\t// Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)\n\t// Otherwise request text input ahead for next frame.\n\tif (g.ActiveId == id && clear_active_id)\n\t\tClearActiveID();\n\telse if (g.ActiveId == id)\n\t\tg.WantTextInputNextFrame = 1;\n\n\t// Render frame\n\tif (!is_multiline)\n\t{\n\t\tRenderNavHighlight(frame_bb, id);\n\t\tRenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);\n\t}\n\n\tconst ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size\n\tImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;\n\tImVec2 text_size(0.0f, 0.0f);\n\n\t// Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line\n\t// without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether.\n\t// Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash.\n\tconst int buf_display_max_length = 2 * 1024 * 1024;\n\tconst char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595\n\tconst char* buf_display_end = NULL; // We have specialized paths below for setting the length\n\tif (is_displaying_hint)\n\t{\n\t\tbuf_display = hint;\n\t\tbuf_display_end = hint + strlen(hint);\n\t}\n\n\t// Render text. We currently only render selection when the widget is active or while scrolling.\n\t// FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive.\n\tif (render_cursor || render_selection)\n\t{\n\t\tIM_ASSERT(state != NULL);\n\t\tif (!is_displaying_hint)\n\t\t\tbuf_display_end = buf_display + state->CurLenA;\n\n\t\t// Render text (with cursor and selection)\n\t\t// This is going to be messy. We need to:\n\t\t// - Display the text (this alone can be more easily clipped)\n\t\t// - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)\n\t\t// - Measure text height (for scrollbar)\n\t\t// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)\n\t\t// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.\n\t\tconst ImWchar* text_begin = state->TextW.Data;\n\t\tImVec2 cursor_offset, select_start_offset;\n\n\t\t{\n\t\t\t// Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.\n\t\t\tconst ImWchar* searches_input_ptr[2] = { NULL, NULL };\n\t\t\tint searches_result_line_no[2] = { -1000, -1000 };\n\t\t\tint searches_remaining = 0;\n\t\t\tif (render_cursor)\n\t\t\t{\n\t\t\t\tsearches_input_ptr[0] = text_begin + state->Stb.cursor;\n\t\t\t\tsearches_result_line_no[0] = -1;\n\t\t\t\tsearches_remaining++;\n\t\t\t}\n\t\t\tif (render_selection)\n\t\t\t{\n\t\t\t\tsearches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);\n\t\t\t\tsearches_result_line_no[1] = -1;\n\t\t\t\tsearches_remaining++;\n\t\t\t}\n\n\t\t\t// Iterate all lines to find our line numbers\n\t\t\t// In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.\n\t\t\tsearches_remaining += is_multiline ? 1 : 0;\n\t\t\tint line_count = 0;\n\t\t\t//for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\\n')) != NULL; s++)  // FIXME-OPT: Could use this when wchar_t are 16-bit\n\t\t\tfor (const ImWchar* s = text_begin; *s != 0; s++)\n\t\t\t\tif (*s == '\\n')\n\t\t\t\t{\n\t\t\t\t\tline_count++;\n\t\t\t\t\tif (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }\n\t\t\t\t\tif (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }\n\t\t\t\t}\n\t\t\tline_count++;\n\t\t\tif (searches_result_line_no[0] == -1)\n\t\t\t\tsearches_result_line_no[0] = line_count;\n\t\t\tif (searches_result_line_no[1] == -1)\n\t\t\t\tsearches_result_line_no[1] = line_count;\n\n\t\t\t// Calculate 2d position by finding the beginning of the line and measuring distance\n\t\t\tcursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;\n\t\t\tcursor_offset.y = searches_result_line_no[0] * g.FontSize;\n\t\t\tif (searches_result_line_no[1] >= 0)\n\t\t\t{\n\t\t\t\tselect_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;\n\t\t\t\tselect_start_offset.y = searches_result_line_no[1] * g.FontSize;\n\t\t\t}\n\n\t\t\t// Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)\n\t\t\tif (is_multiline)\n\t\t\t\ttext_size = ImVec2(inner_size.x, line_count * g.FontSize);\n\t\t}\n\n\t\t// Scroll\n\t\tif (render_cursor && state->CursorFollow)\n\t\t{\n\t\t\t// Horizontal scroll in chunks of quarter width\n\t\t\tif (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))\n\t\t\t{\n\t\t\t\tconst float scroll_increment_x = inner_size.x * 0.25f;\n\t\t\t\tconst float visible_width = inner_size.x - style.FramePadding.x;\n\t\t\t\tif (cursor_offset.x < state->ScrollX)\n\t\t\t\t\tstate->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x));\n\t\t\t\telse if (cursor_offset.x - visible_width >= state->ScrollX)\n\t\t\t\t\tstate->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstate->ScrollX = 0.0f;\n\t\t\t}\n\n\t\t\t// Vertical scroll\n\t\t\tif (is_multiline)\n\t\t\t{\n\t\t\t\t// Test if cursor is vertically visible\n\t\t\t\tif (cursor_offset.y - g.FontSize < scroll_y)\n\t\t\t\t\tscroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);\n\t\t\t\telse if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y)\n\t\t\t\t\tscroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;\n\t\t\t\tconst float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f);\n\t\t\t\tscroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y);\n\t\t\t\tdraw_pos.y += (draw_window->Scroll.y - scroll_y);   // Manipulate cursor pos immediately avoid a frame of lag\n\t\t\t\tdraw_window->Scroll.y = scroll_y;\n\t\t\t}\n\n\t\t\tstate->CursorFollow = false;\n\t\t}\n\n\t\t// Draw selection\n\t\tconst ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);\n\t\tif (render_selection)\n\t\t{\n\t\t\tconst ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);\n\t\t\tconst ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);\n\n\t\t\tImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.\n\t\t\tfloat bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.\n\t\t\tfloat bg_offy_dn = is_multiline ? 0.0f : 2.0f;\n\t\t\tImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;\n\t\t\tfor (const ImWchar* p = text_selected_begin; p < text_selected_end; )\n\t\t\t{\n\t\t\t\tif (rect_pos.y > clip_rect.w + g.FontSize)\n\t\t\t\t\tbreak;\n\t\t\t\tif (rect_pos.y < clip_rect.y)\n\t\t\t\t{\n\t\t\t\t\t//p = (const ImWchar*)wmemchr((const wchar_t*)p, '\\n', text_selected_end - p);  // FIXME-OPT: Could use this when wchar_t are 16-bit\n\t\t\t\t\t//p = p ? p + 1 : text_selected_end;\n\t\t\t\t\twhile (p < text_selected_end)\n\t\t\t\t\t\tif (*p++ == '\\n')\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true);\n\t\t\t\t\tif (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines\n\t\t\t\t\tImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));\n\t\t\t\t\trect.ClipWith(clip_rect);\n\t\t\t\t\tif (rect.Overlaps(clip_rect))\n\t\t\t\t\t\tdraw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);\n\t\t\t\t}\n\t\t\t\trect_pos.x = draw_pos.x - draw_scroll.x;\n\t\t\t\trect_pos.y += g.FontSize;\n\t\t\t}\n\t\t}\n\n\t\t// We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.\n\t\tif (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)\n\t\t{\n\t\t\tImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);\n\t\t\tdraw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);\n\t\t}\n\n\t\t// Draw blinking cursor\n\t\tif (render_cursor)\n\t\t{\n\t\t\tstate->CursorAnim += io.DeltaTime;\n\t\t\tbool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;\n\t\t\tImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_scroll);\n\t\t\tImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);\n\t\t\tif (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))\n\t\t\t\tdraw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));\n\n\t\t\t// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)\n\t\t\tif (!is_readonly)\n\t\t\t{\n\t\t\t\tg.PlatformImeData.WantVisible = true;\n\t\t\t\tg.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize);\n\t\t\t\tg.PlatformImeData.InputLineHeight = g.FontSize;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Render text only (no selection, no cursor)\n\t\tif (is_multiline)\n\t\t\ttext_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width\n\t\telse if (!is_displaying_hint && g.ActiveId == id)\n\t\t\tbuf_display_end = buf_display + state->CurLenA;\n\t\telse if (!is_displaying_hint)\n\t\t\tbuf_display_end = buf_display + strlen(buf_display);\n\n\t\tif (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)\n\t\t{\n\t\t\tImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);\n\t\t\tdraw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);\n\t\t}\n\t}\n\n\tif (is_password && !is_displaying_hint)\n\t\tPopFont();\n\n\tif (is_multiline)\n\t{\n\t\t// For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)...\n\t\tDummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y));\n\t\tg.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;\n\t\tEndChild();\n\t\titem_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow);\n\n\t\t// ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active...\n\t\t// FIXME: This quite messy/tricky, should attempt to get rid of the child window.\n\t\tEndGroup();\n\t\tif (g.LastItemData.ID == 0)\n\t\t{\n\t\t\tg.LastItemData.ID = id;\n\t\t\tg.LastItemData.InFlags = item_data_backup.InFlags;\n\t\t\tg.LastItemData.StatusFlags = item_data_backup.StatusFlags;\n\t\t}\n\t}\n\n\t// Log as text\n\tif (g.LogEnabled && (!is_password || is_displaying_hint))\n\t{\n\t\tLogSetNextTextDecoration(\"{\", \"}\");\n\t\tLogRenderedText(&draw_pos, buf_display, buf_display_end);\n\t}\n\n\tif (label_size.x > 0)\n\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);\n\n\tif (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))\n\t\tMarkItemEdited(id);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);\n\tif ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)\n\t\treturn validated;\n\telse\n\t\treturn value_changed;\n}\n\nvoid ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)\n{\n#ifndef IMGUI_DISABLE_DEBUG_TOOLS\n\tImGuiContext& g = *GImGui;\n\tImStb::STB_TexteditState* stb_state = &state->Stb;\n\tImStb::StbUndoState* undo_state = &stb_state->undostate;\n\tText(\"ID: 0x%08X, ActiveID: 0x%08X\", state->ID, g.ActiveId);\n\tDebugLocateItemOnHover(state->ID);\n\tText(\"CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d\", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end);\n\tText(\"has_preferred_x: %d (%.2f)\", stb_state->has_preferred_x, stb_state->preferred_x);\n\tText(\"undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d\", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point);\n\tif (BeginChild(\"undopoints\", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state\n\t{\n\t\tPushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));\n\t\tfor (int n = 0; n < STB_TEXTEDIT_UNDOSTATECOUNT; n++)\n\t\t{\n\t\t\tImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n];\n\t\t\tconst char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' ';\n\t\t\tif (undo_rec_type == ' ')\n\t\t\t\tBeginDisabled();\n\t\t\tchar buf[64] = \"\";\n\t\t\tif (undo_rec_type != ' ' && undo_rec->char_storage != -1)\n\t\t\t\tImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length);\n\t\t\tText(\"%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \\\"%s\\\"\",\n\t\t\t\tundo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf);\n\t\t\tif (undo_rec_type == ' ')\n\t\t\t\tEndDisabled();\n\t\t}\n\t\tPopStyleVar();\n\t}\n\tEndChild();\n#else\n\tIM_UNUSED(state);\n#endif\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc.\n//-------------------------------------------------------------------------\n// - ColorEdit3()\n// - ColorEdit4()\n// - ColorPicker3()\n// - RenderColorRectWithAlphaCheckerboard() [Internal]\n// - ColorPicker4()\n// - ColorButton()\n// - SetColorEditOptions()\n// - ColorTooltip() [Internal]\n// - ColorEditOptionsPopup() [Internal]\n// - ColorPickerOptionsPopup() [Internal]\n//-------------------------------------------------------------------------\n\nbool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags)\n{\n\treturn ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);\n}\n\nstatic void ColorEditRestoreH(const float* col, float* H)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.ColorEditCurrentID != 0);\n\tif (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))\n\t\treturn;\n\t*H = g.ColorEditSavedHue;\n}\n\n// ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation.\n// Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting.\nstatic void ColorEditRestoreHS(const float* col, float* H, float* S, float* V)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(g.ColorEditCurrentID != 0);\n\tif (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))\n\t\treturn;\n\n\t// When S == 0, H is undefined.\n\t// When H == 1 it wraps around to 0.\n\tif (*S == 0.0f || (*H == 0.0f && g.ColorEditSavedHue == 1))\n\t\t*H = g.ColorEditSavedHue;\n\n\t// When V == 0, S is undefined.\n\tif (*V == 0.0f)\n\t\t*S = g.ColorEditSavedSat;\n}\n\n// Edit colors components (each component in 0.0f..1.0f range).\n// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.\n// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.\nbool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst float square_sz = GetFrameHeight();\n\tconst float w_full = CalcItemWidth();\n\tconst float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);\n\tconst float w_inputs = w_full - w_button;\n\tconst char* label_display_end = FindRenderedTextEnd(label);\n\tg.NextItemData.ClearFlags();\n\n\tBeginGroup();\n\tPushID(label);\n\tconst bool set_current_color_edit_id = (g.ColorEditCurrentID == 0);\n\tif (set_current_color_edit_id)\n\t\tg.ColorEditCurrentID = window->IDStack.back();\n\n\t// If we're not showing any slider there's no point in doing any HSV conversions\n\tconst ImGuiColorEditFlags flags_untouched = flags;\n\tif (flags & ImGuiColorEditFlags_NoInputs)\n\t\tflags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions;\n\n\t// Context menu: display and modify options (before defaults are applied)\n\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\tColorEditOptionsPopup(col, flags);\n\n\t// Read stored options\n\tif (!(flags & ImGuiColorEditFlags_DisplayMask_))\n\t\tflags |= (g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_);\n\tif (!(flags & ImGuiColorEditFlags_DataTypeMask_))\n\t\tflags |= (g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_);\n\tif (!(flags & ImGuiColorEditFlags_PickerMask_))\n\t\tflags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_);\n\tif (!(flags & ImGuiColorEditFlags_InputMask_))\n\t\tflags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_);\n\tflags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_));\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));   // Check that only 1 is selected\n\n\tconst bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;\n\tconst bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;\n\tconst int components = alpha ? 4 : 3;\n\n\t// Convert to the formats we need\n\tfloat f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };\n\tif ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB))\n\t\tColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);\n\telse if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV))\n\t{\n\t\t// Hue is lost when converting from grayscale rgb (saturation=0). Restore it.\n\t\tColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);\n\t\tColorEditRestoreHS(col, &f[0], &f[1], &f[2]);\n\t}\n\tint i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) };\n\n\tbool value_changed = false;\n\tbool value_changed_as_float = false;\n\n\tconst ImVec2 pos = window->DC.CursorPos;\n\tconst float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f;\n\twindow->DC.CursorPos.x = pos.x + inputs_offset_x;\n\n\tif ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)\n\t{\n\t\t// RGB/HSV 0..255 Sliders\n\t\tconst float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));\n\t\tconst float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));\n\n\t\tconst bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? \"M:0.000\" : \"M:000\").x);\n\t\tstatic const char* ids[4] = { \"##X\", \"##Y\", \"##Z\", \"##W\" };\n\t\tstatic const char* fmt_table_int[3][4] =\n\t\t{\n\t\t\t{   \"%3d\",   \"%3d\",   \"%3d\",   \"%3d\" }, // Short display\n\t\t\t{ \"R:%3d\", \"G:%3d\", \"B:%3d\", \"A:%3d\" }, // Long display for RGBA\n\t\t\t{ \"H:%3d\", \"S:%3d\", \"V:%3d\", \"A:%3d\" }  // Long display for HSVA\n\t\t};\n\t\tstatic const char* fmt_table_float[3][4] =\n\t\t{\n\t\t\t{   \"%0.3f\",   \"%0.3f\",   \"%0.3f\",   \"%0.3f\" }, // Short display\n\t\t\t{ \"R:%0.3f\", \"G:%0.3f\", \"B:%0.3f\", \"A:%0.3f\" }, // Long display for RGBA\n\t\t\t{ \"H:%0.3f\", \"S:%0.3f\", \"V:%0.3f\", \"A:%0.3f\" }  // Long display for HSVA\n\t\t};\n\t\tconst int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1;\n\n\t\tfor (int n = 0; n < components; n++)\n\t\t{\n\t\t\tif (n > 0)\n\t\t\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\t\tSetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last);\n\n\t\t\t// FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0.\n\t\t\tif (flags & ImGuiColorEditFlags_Float)\n\t\t\t{\n\t\t\t\tvalue_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);\n\t\t\t\tvalue_changed_as_float |= value_changed;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvalue_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);\n\t\t\t}\n\t\t\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\t\t\tOpenPopupOnItemClick(\"context\", ImGuiPopupFlags_MouseButtonRight);\n\t\t}\n\t}\n\telse if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)\n\t{\n\t\t// RGB Hexadecimal Input\n\t\tchar buf[64];\n\t\tif (alpha)\n\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"#%02X%02X%02X%02X\", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255));\n\t\telse\n\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"#%02X%02X%02X\", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255));\n\t\tSetNextItemWidth(w_inputs);\n\t\tif (InputText(\"##Text\", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))\n\t\t{\n\t\t\tvalue_changed = true;\n\t\t\tchar* p = buf;\n\t\t\twhile (*p == '#' || ImCharIsBlankA(*p))\n\t\t\t\tp++;\n\t\t\ti[0] = i[1] = i[2] = 0;\n\t\t\ti[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. inputting #FFFFFF omitting alpha)\n\t\t\tint r;\n\t\t\tif (alpha)\n\t\t\t\tr = sscanf(p, \"%02X%02X%02X%02X\", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned)\n\t\t\telse\n\t\t\t\tr = sscanf(p, \"%02X%02X%02X\", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);\n\t\t\tIM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'.\n\t\t}\n\t\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\t\tOpenPopupOnItemClick(\"context\", ImGuiPopupFlags_MouseButtonRight);\n\t}\n\n\tImGuiWindow* picker_active_window = NULL;\n\tif (!(flags & ImGuiColorEditFlags_NoSmallPreview))\n\t{\n\t\tconst float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x;\n\t\twindow->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y);\n\n\t\tconst ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);\n\t\tif (ColorButton(\"##ColorButton\", col_v4, flags))\n\t\t{\n\t\t\tif (!(flags & ImGuiColorEditFlags_NoPicker))\n\t\t\t{\n\t\t\t\t// Store current color and open a picker\n\t\t\t\tg.ColorPickerRef = col_v4;\n\t\t\t\tOpenPopup(\"picker\");\n\t\t\t\tSetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(0.0f, style.ItemSpacing.y));\n\t\t\t}\n\t\t}\n\t\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\t\tOpenPopupOnItemClick(\"context\", ImGuiPopupFlags_MouseButtonRight);\n\n\t\tif (BeginPopup(\"picker\"))\n\t\t{\n\t\t\tif (g.CurrentWindow->BeginCount == 1)\n\t\t\t{\n\t\t\t\tpicker_active_window = g.CurrentWindow;\n\t\t\t\tif (label != label_display_end)\n\t\t\t\t{\n\t\t\t\t\tTextEx(label, label_display_end);\n\t\t\t\t\tSpacing();\n\t\t\t\t}\n\t\t\t\tImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;\n\t\t\t\tImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;\n\t\t\t\tSetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?\n\t\t\t\tvalue_changed |= ColorPicker4(\"##picker\", col, picker_flags, &g.ColorPickerRef.x);\n\t\t\t}\n\t\t\tEndPopup();\n\t\t}\n\t}\n\n\tif (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))\n\t{\n\t\t// Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left),\n\t\t// but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this.\n\t\tSameLine(0.0f, style.ItemInnerSpacing.x);\n\t\twindow->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x);\n\t\tTextEx(label, label_display_end);\n\t}\n\n\t// Convert back\n\tif (value_changed && picker_active_window == NULL)\n\t{\n\t\tif (!value_changed_as_float)\n\t\t\tfor (int n = 0; n < 4; n++)\n\t\t\t\tf[n] = i[n] / 255.0f;\n\t\tif ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB))\n\t\t{\n\t\t\tg.ColorEditSavedHue = f[0];\n\t\t\tg.ColorEditSavedSat = f[1];\n\t\t\tColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);\n\t\t\tg.ColorEditSavedID = g.ColorEditCurrentID;\n\t\t\tg.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0));\n\t\t}\n\t\tif ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV))\n\t\t\tColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);\n\n\t\tcol[0] = f[0];\n\t\tcol[1] = f[1];\n\t\tcol[2] = f[2];\n\t\tif (alpha)\n\t\t\tcol[3] = f[3];\n\t}\n\n\tif (set_current_color_edit_id)\n\t\tg.ColorEditCurrentID = 0;\n\tPopID();\n\tEndGroup();\n\n\t// Drag and Drop Target\n\t// NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.\n\tif ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget())\n\t{\n\t\tbool accepted_drag_drop = false;\n\t\tif (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))\n\t\t{\n\t\t\tmemcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086\n\t\t\tvalue_changed = accepted_drag_drop = true;\n\t\t}\n\t\tif (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))\n\t\t{\n\t\t\tmemcpy((float*)col, payload->Data, sizeof(float) * components);\n\t\t\tvalue_changed = accepted_drag_drop = true;\n\t\t}\n\n\t\t// Drag-drop payloads are always RGB\n\t\tif (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV))\n\t\t\tColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]);\n\t\tEndDragDropTarget();\n\t}\n\n\t// When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().\n\tif (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)\n\t\tg.LastItemData.ID = g.ActiveId;\n\n\tif (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId\n\t\tMarkItemEdited(g.LastItemData.ID);\n\n\treturn value_changed;\n}\n\nbool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags)\n{\n\tfloat col4[4] = { col[0], col[1], col[2], 1.0f };\n\tif (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha))\n\t\treturn false;\n\tcol[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];\n\treturn true;\n}\n\n// Helper for ColorPicker4()\nstatic void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha)\n{\n\tImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha);\n\tImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0, 0, 0, alpha8));\n\tImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255, 255, 255, alpha8));\n\tImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0, 0, 0, alpha8));\n\tImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255, 255, 255, alpha8));\n}\n\n// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.\n// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.)\n// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)\n// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0)\nbool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImDrawList* draw_list = window->DrawList;\n\tImGuiStyle& style = g.Style;\n\tImGuiIO& io = g.IO;\n\n\tconst float width = CalcItemWidth();\n\tg.NextItemData.ClearFlags();\n\n\tPushID(label);\n\tconst bool set_current_color_edit_id = (g.ColorEditCurrentID == 0);\n\tif (set_current_color_edit_id)\n\t\tg.ColorEditCurrentID = window->IDStack.back();\n\tBeginGroup();\n\n\tif (!(flags & ImGuiColorEditFlags_NoSidePreview))\n\t\tflags |= ImGuiColorEditFlags_NoSmallPreview;\n\n\t// Context menu: display and store options.\n\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\tColorPickerOptionsPopup(col, flags);\n\n\t// Read stored options\n\tif (!(flags & ImGuiColorEditFlags_PickerMask_))\n\t\tflags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_;\n\tif (!(flags & ImGuiColorEditFlags_InputMask_))\n\t\tflags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_;\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));  // Check that only 1 is selected\n\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\tflags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar);\n\n\t// Setup\n\tint components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4;\n\tbool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha);\n\tImVec2 picker_pos = window->DC.CursorPos;\n\tfloat square_sz = GetFrameHeight();\n\tfloat bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars\n\tfloat sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box\n\tfloat bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;\n\tfloat bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;\n\tfloat bars_triangles_half_sz = IM_FLOOR(bars_width * 0.20f);\n\n\tfloat backup_initial_col[4];\n\tmemcpy(backup_initial_col, col, components * sizeof(float));\n\n\tfloat wheel_thickness = sv_picker_size * 0.08f;\n\tfloat wheel_r_outer = sv_picker_size * 0.50f;\n\tfloat wheel_r_inner = wheel_r_outer - wheel_thickness;\n\tImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width) * 0.5f, picker_pos.y + sv_picker_size * 0.5f);\n\n\t// Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic.\n\tfloat triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);\n\tImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point.\n\tImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point.\n\tImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point.\n\n\tfloat H = col[0], S = col[1], V = col[2];\n\tfloat R = col[0], G = col[1], B = col[2];\n\tif (flags & ImGuiColorEditFlags_InputRGB)\n\t{\n\t\t// Hue is lost when converting from grayscale rgb (saturation=0). Restore it.\n\t\tColorConvertRGBtoHSV(R, G, B, H, S, V);\n\t\tColorEditRestoreHS(col, &H, &S, &V);\n\t}\n\telse if (flags & ImGuiColorEditFlags_InputHSV)\n\t{\n\t\tColorConvertHSVtoRGB(H, S, V, R, G, B);\n\t}\n\n\tbool value_changed = false, value_changed_h = false, value_changed_sv = false;\n\n\tPushItemFlag(ImGuiItemFlags_NoNav, true);\n\tif (flags & ImGuiColorEditFlags_PickerHueWheel)\n\t{\n\t\t// Hue wheel + SV triangle logic\n\t\tInvisibleButton(\"hsv\", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));\n\t\tif (IsItemActive())\n\t\t{\n\t\t\tImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center;\n\t\t\tImVec2 current_off = g.IO.MousePos - wheel_center;\n\t\t\tfloat initial_dist2 = ImLengthSqr(initial_off);\n\t\t\tif (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1))\n\t\t\t{\n\t\t\t\t// Interactive with Hue wheel\n\t\t\t\tH = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f;\n\t\t\t\tif (H < 0.0f)\n\t\t\t\t\tH += 1.0f;\n\t\t\t\tvalue_changed = value_changed_h = true;\n\t\t\t}\n\t\t\tfloat cos_hue_angle = ImCos(-H * 2.0f * IM_PI);\n\t\t\tfloat sin_hue_angle = ImSin(-H * 2.0f * IM_PI);\n\t\t\tif (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))\n\t\t\t{\n\t\t\t\t// Interacting with SV triangle\n\t\t\t\tImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);\n\t\t\t\tif (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated))\n\t\t\t\t\tcurrent_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);\n\t\t\t\tfloat uu, vv, ww;\n\t\t\t\tImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww);\n\t\t\t\tV = ImClamp(1.0f - vv, 0.0001f, 1.0f);\n\t\t\t\tS = ImClamp(uu / V, 0.0001f, 1.0f);\n\t\t\t\tvalue_changed = value_changed_sv = true;\n\t\t\t}\n\t\t}\n\t\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\t\tOpenPopupOnItemClick(\"context\", ImGuiPopupFlags_MouseButtonRight);\n\t}\n\telse if (flags & ImGuiColorEditFlags_PickerHueBar)\n\t{\n\t\t// SV rectangle logic\n\t\tInvisibleButton(\"sv\", ImVec2(sv_picker_size, sv_picker_size));\n\t\tif (IsItemActive())\n\t\t{\n\t\t\tS = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1));\n\t\t\tV = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));\n\t\t\tColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square.\n\t\t\tvalue_changed = value_changed_sv = true;\n\t\t}\n\t\tif (!(flags & ImGuiColorEditFlags_NoOptions))\n\t\t\tOpenPopupOnItemClick(\"context\", ImGuiPopupFlags_MouseButtonRight);\n\n\t\t// Hue bar logic\n\t\tSetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));\n\t\tInvisibleButton(\"hue\", ImVec2(bars_width, sv_picker_size));\n\t\tif (IsItemActive())\n\t\t{\n\t\t\tH = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));\n\t\t\tvalue_changed = value_changed_h = true;\n\t\t}\n\t}\n\n\t// Alpha bar logic\n\tif (alpha_bar)\n\t{\n\t\tSetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));\n\t\tInvisibleButton(\"alpha\", ImVec2(bars_width, sv_picker_size));\n\t\tif (IsItemActive())\n\t\t{\n\t\t\tcol[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));\n\t\t\tvalue_changed = true;\n\t\t}\n\t}\n\tPopItemFlag(); // ImGuiItemFlags_NoNav\n\n\tif (!(flags & ImGuiColorEditFlags_NoSidePreview))\n\t{\n\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\tBeginGroup();\n\t}\n\n\tif (!(flags & ImGuiColorEditFlags_NoLabel))\n\t{\n\t\tconst char* label_display_end = FindRenderedTextEnd(label);\n\t\tif (label != label_display_end)\n\t\t{\n\t\t\tif ((flags & ImGuiColorEditFlags_NoSidePreview))\n\t\t\t\tSameLine(0, style.ItemInnerSpacing.x);\n\t\t\tTextEx(label, label_display_end);\n\t\t}\n\t}\n\n\tif (!(flags & ImGuiColorEditFlags_NoSidePreview))\n\t{\n\t\tPushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);\n\t\tImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);\n\t\tif ((flags & ImGuiColorEditFlags_NoLabel))\n\t\t\tText(\"Current\");\n\n\t\tImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip;\n\t\tColorButton(\"##current\", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2));\n\t\tif (ref_col != NULL)\n\t\t{\n\t\t\tText(\"Original\");\n\t\t\tImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);\n\t\t\tif (ColorButton(\"##original\", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)))\n\t\t\t{\n\t\t\t\tmemcpy(col, ref_col, components * sizeof(float));\n\t\t\t\tvalue_changed = true;\n\t\t\t}\n\t\t}\n\t\tPopItemFlag();\n\t\tEndGroup();\n\t}\n\n\t// Convert back color to RGB\n\tif (value_changed_h || value_changed_sv)\n\t{\n\t\tif (flags & ImGuiColorEditFlags_InputRGB)\n\t\t{\n\t\t\tColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]);\n\t\t\tg.ColorEditSavedHue = H;\n\t\t\tg.ColorEditSavedSat = S;\n\t\t\tg.ColorEditSavedID = g.ColorEditCurrentID;\n\t\t\tg.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0));\n\t\t}\n\t\telse if (flags & ImGuiColorEditFlags_InputHSV)\n\t\t{\n\t\t\tcol[0] = H;\n\t\t\tcol[1] = S;\n\t\t\tcol[2] = V;\n\t\t}\n\t}\n\n\t// R,G,B and H,S,V slider color editor\n\tbool value_changed_fix_hue_wrap = false;\n\tif ((flags & ImGuiColorEditFlags_NoInputs) == 0)\n\t{\n\t\tPushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);\n\t\tImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf;\n\t\tImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;\n\t\tif (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)\n\t\t\tif (ColorEdit4(\"##rgb\", col, sub_flags | ImGuiColorEditFlags_DisplayRGB))\n\t\t\t{\n\t\t\t\t// FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget.\n\t\t\t\t// For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050)\n\t\t\t\tvalue_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap);\n\t\t\t\tvalue_changed = true;\n\t\t\t}\n\t\tif (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)\n\t\t\tvalue_changed |= ColorEdit4(\"##hsv\", col, sub_flags | ImGuiColorEditFlags_DisplayHSV);\n\t\tif (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)\n\t\t\tvalue_changed |= ColorEdit4(\"##hex\", col, sub_flags | ImGuiColorEditFlags_DisplayHex);\n\t\tPopItemWidth();\n\t}\n\n\t// Try to cancel hue wrap (after ColorEdit4 call), if any\n\tif (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB))\n\t{\n\t\tfloat new_H, new_S, new_V;\n\t\tColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);\n\t\tif (new_H <= 0 && H > 0)\n\t\t{\n\t\t\tif (new_V <= 0 && V != new_V)\n\t\t\t\tColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);\n\t\t\telse if (new_S <= 0)\n\t\t\t\tColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]);\n\t\t}\n\t}\n\n\tif (value_changed)\n\t{\n\t\tif (flags & ImGuiColorEditFlags_InputRGB)\n\t\t{\n\t\t\tR = col[0];\n\t\t\tG = col[1];\n\t\t\tB = col[2];\n\t\t\tColorConvertRGBtoHSV(R, G, B, H, S, V);\n\t\t\tColorEditRestoreHS(col, &H, &S, &V);   // Fix local Hue as display below will use it immediately.\n\t\t}\n\t\telse if (flags & ImGuiColorEditFlags_InputHSV)\n\t\t{\n\t\t\tH = col[0];\n\t\t\tS = col[1];\n\t\t\tV = col[2];\n\t\t\tColorConvertHSVtoRGB(H, S, V, R, G, B);\n\t\t}\n\t}\n\n\tconst int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha);\n\tconst ImU32 col_black = IM_COL32(0, 0, 0, style_alpha8);\n\tconst ImU32 col_white = IM_COL32(255, 255, 255, style_alpha8);\n\tconst ImU32 col_midgrey = IM_COL32(128, 128, 128, style_alpha8);\n\tconst ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) };\n\n\tImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);\n\tImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);\n\tImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!!\n\n\tImVec2 sv_cursor_pos;\n\n\tif (flags & ImGuiColorEditFlags_PickerHueWheel)\n\t{\n\t\t// Render Hue Wheel\n\t\tconst float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).\n\t\tconst int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);\n\t\tfor (int n = 0; n < 6; n++)\n\t\t{\n\t\t\tconst float a0 = (n) / 6.0f * 2.0f * IM_PI - aeps;\n\t\t\tconst float a1 = (n + 1.0f) / 6.0f * 2.0f * IM_PI + aeps;\n\t\t\tconst int vert_start_idx = draw_list->VtxBuffer.Size;\n\t\t\tdraw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer) * 0.5f, a0, a1, segment_per_arc);\n\t\t\tdraw_list->PathStroke(col_white, 0, wheel_thickness);\n\t\t\tconst int vert_end_idx = draw_list->VtxBuffer.Size;\n\n\t\t\t// Paint colors over existing vertices\n\t\t\tImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner);\n\t\t\tImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner);\n\t\t\tShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]);\n\t\t}\n\n\t\t// Render Cursor + preview on Hue Wheel\n\t\tfloat cos_hue_angle = ImCos(H * 2.0f * IM_PI);\n\t\tfloat sin_hue_angle = ImSin(H * 2.0f * IM_PI);\n\t\tImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f);\n\t\tfloat hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;\n\t\tint hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others.\n\t\tdraw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);\n\t\tdraw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments);\n\t\tdraw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments);\n\n\t\t// Render SV triangle (rotated according to hue)\n\t\tImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);\n\t\tImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);\n\t\tImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);\n\t\tImVec2 uv_white = GetFontTexUvWhitePixel();\n\t\tdraw_list->PrimReserve(3, 3);\n\t\tdraw_list->PrimVtx(tra, uv_white, hue_color32);\n\t\tdraw_list->PrimVtx(trb, uv_white, col_black);\n\t\tdraw_list->PrimVtx(trc, uv_white, col_white);\n\t\tdraw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);\n\t\tsv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));\n\t}\n\telse if (flags & ImGuiColorEditFlags_PickerHueBar)\n\t{\n\t\t// Render SV Square\n\t\tdraw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white);\n\t\tdraw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black);\n\t\tRenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);\n\t\tsv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much\n\t\tsv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);\n\n\t\t// Render Hue Bar\n\t\tfor (int i = 0; i < 6; ++i)\n\t\t\tdraw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]);\n\t\tfloat bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size);\n\t\tRenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);\n\t\tRenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);\n\t}\n\n\t// Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)\n\tfloat sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;\n\tint sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others.\n\tdraw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments);\n\tdraw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments);\n\tdraw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments);\n\n\t// Render alpha bar\n\tif (alpha_bar)\n\t{\n\t\tfloat alpha = ImSaturate(col[3]);\n\t\tImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);\n\t\tRenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));\n\t\tdraw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK);\n\t\tfloat bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size);\n\t\tRenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);\n\t\tRenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);\n\t}\n\n\tEndGroup();\n\n\tif (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0)\n\t\tvalue_changed = false;\n\tif (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId\n\t\tMarkItemEdited(g.LastItemData.ID);\n\n\tif (set_current_color_edit_id)\n\t\tg.ColorEditCurrentID = 0;\n\tPopID();\n\n\treturn value_changed;\n}\n\n// A little color square. Return true when clicked.\n// FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.\n// 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip.\n// Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set.\nbool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, const ImVec2& size_arg)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiID id = window->GetID(desc_id);\n\tconst float default_size = GetFrameHeight();\n\tconst ImVec2 size(size_arg.x == 0.0f ? default_size : size_arg.x, size_arg.y == 0.0f ? default_size : size_arg.y);\n\tconst ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);\n\tItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f);\n\tif (!ItemAdd(bb, id))\n\t\treturn false;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held);\n\n\tif (flags & ImGuiColorEditFlags_NoAlpha)\n\t\tflags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf);\n\n\tImVec4 col_rgb = col;\n\tif (flags & ImGuiColorEditFlags_InputHSV)\n\t\tColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z);\n\n\tImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f);\n\tfloat grid_step = ImMin(size.x, size.y) / 2.99f;\n\tfloat rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f);\n\tImRect bb_inner = bb;\n\tfloat off = 0.0f;\n\tif ((flags & ImGuiColorEditFlags_NoBorder) == 0)\n\t{\n\t\toff = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts.\n\t\tbb_inner.Expand(off);\n\t}\n\tif ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f)\n\t{\n\t\tfloat mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f);\n\t\tRenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight);\n\t\twindow->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft);\n\t}\n\telse\n\t{\n\t\t// Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha\n\t\tImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha;\n\t\tif (col_source.w < 1.0f)\n\t\t\tRenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);\n\t\telse\n\t\t\twindow->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding);\n\t}\n\tRenderNavHighlight(bb, id);\n\tif ((flags & ImGuiColorEditFlags_NoBorder) == 0)\n\t{\n\t\tif (g.Style.FrameBorderSize > 0.0f)\n\t\t\tRenderFrameBorder(bb.Min, bb.Max, rounding);\n\t\telse\n\t\t\twindow->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border\n\t}\n\n\t// Drag and Drop Source\n\t// NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test.\n\tif (g.ActiveId == id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource())\n\t{\n\t\tif (flags & ImGuiColorEditFlags_NoAlpha)\n\t\t\tSetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once);\n\t\telse\n\t\t\tSetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once);\n\t\tColorButton(desc_id, col, flags);\n\t\tSameLine();\n\t\tTextEx(\"Color\");\n\t\tEndDragDropSource();\n\t}\n\n\t// Tooltip\n\tif (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip))\n\t\tColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));\n\n\treturn pressed;\n}\n\n// Initialize/override default color options\nvoid ImGui::SetColorEditOptions(ImGuiColorEditFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tif ((flags & ImGuiColorEditFlags_DisplayMask_) == 0)\n\t\tflags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_;\n\tif ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0)\n\t\tflags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_;\n\tif ((flags & ImGuiColorEditFlags_PickerMask_) == 0)\n\t\tflags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_;\n\tif ((flags & ImGuiColorEditFlags_InputMask_) == 0)\n\t\tflags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_;\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_));    // Check only 1 option is selected\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_));   // Check only 1 option is selected\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_));     // Check only 1 option is selected\n\tIM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));      // Check only 1 option is selected\n\tg.ColorEditOptions = flags;\n}\n\n// Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.\nvoid ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\n\tif (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))\n\t\treturn;\n\tconst char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;\n\tif (text_end > text)\n\t{\n\t\tTextEx(text, text_end);\n\t\tSeparator();\n\t}\n\n\tImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2);\n\tImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);\n\tint cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);\n\tColorButton(\"##preview\", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz);\n\tSameLine();\n\tif ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_))\n\t{\n\t\tif (flags & ImGuiColorEditFlags_NoAlpha)\n\t\t\tText(\"#%02X%02X%02X\\nR: %d, G: %d, B: %d\\n(%.3f, %.3f, %.3f)\", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]);\n\t\telse\n\t\t\tText(\"#%02X%02X%02X%02X\\nR:%d, G:%d, B:%d, A:%d\\n(%.3f, %.3f, %.3f, %.3f)\", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]);\n\t}\n\telse if (flags & ImGuiColorEditFlags_InputHSV)\n\t{\n\t\tif (flags & ImGuiColorEditFlags_NoAlpha)\n\t\t\tText(\"H: %.3f, S: %.3f, V: %.3f\", col[0], col[1], col[2]);\n\t\telse\n\t\t\tText(\"H: %.3f, S: %.3f, V: %.3f, A: %.3f\", col[0], col[1], col[2], col[3]);\n\t}\n\tEndTooltip();\n}\n\nvoid ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)\n{\n\tbool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_);\n\tbool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_);\n\tif ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup(\"context\"))\n\t\treturn;\n\tImGuiContext& g = *GImGui;\n\tg.LockMarkEdited++;\n\tImGuiColorEditFlags opts = g.ColorEditOptions;\n\tif (allow_opt_inputs)\n\t{\n\t\tif (RadioButton(\"RGB\", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB;\n\t\tif (RadioButton(\"HSV\", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV;\n\t\tif (RadioButton(\"Hex\", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex;\n\t}\n\tif (allow_opt_datatype)\n\t{\n\t\tif (allow_opt_inputs) Separator();\n\t\tif (RadioButton(\"0..255\", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8;\n\t\tif (RadioButton(\"0.00..1.00\", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float;\n\t}\n\n\tif (allow_opt_inputs || allow_opt_datatype)\n\t\tSeparator();\n\tif (Button(\"Copy as..\", ImVec2(-1, 0)))\n\t\tOpenPopup(\"Copy\");\n\tif (BeginPopup(\"Copy\"))\n\t{\n\t\tint cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);\n\t\tchar buf[64];\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"(%.3ff, %.3ff, %.3ff, %.3ff)\", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);\n\t\tif (Selectable(buf))\n\t\t\tSetClipboardText(buf);\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"(%d,%d,%d,%d)\", cr, cg, cb, ca);\n\t\tif (Selectable(buf))\n\t\t\tSetClipboardText(buf);\n\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"#%02X%02X%02X\", cr, cg, cb);\n\t\tif (Selectable(buf))\n\t\t\tSetClipboardText(buf);\n\t\tif (!(flags & ImGuiColorEditFlags_NoAlpha))\n\t\t{\n\t\t\tImFormatString(buf, IM_ARRAYSIZE(buf), \"#%02X%02X%02X%02X\", cr, cg, cb, ca);\n\t\t\tif (Selectable(buf))\n\t\t\t\tSetClipboardText(buf);\n\t\t}\n\t\tEndPopup();\n\t}\n\n\tg.ColorEditOptions = opts;\n\tEndPopup();\n\tg.LockMarkEdited--;\n}\n\nvoid ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags)\n{\n\tbool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_);\n\tbool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);\n\tif ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup(\"context\"))\n\t\treturn;\n\tImGuiContext& g = *GImGui;\n\tg.LockMarkEdited++;\n\tif (allow_opt_picker)\n\t{\n\t\tImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function\n\t\tPushItemWidth(picker_size.x);\n\t\tfor (int picker_type = 0; picker_type < 2; picker_type++)\n\t\t{\n\t\t\t// Draw small/thumbnail version of each picker type (over an invisible button for selection)\n\t\t\tif (picker_type > 0) Separator();\n\t\t\tPushID(picker_type);\n\t\t\tImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha);\n\t\t\tif (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;\n\t\t\tif (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;\n\t\t\tImVec2 backup_pos = GetCursorScreenPos();\n\t\t\tif (Selectable(\"##selectable\", false, 0, picker_size)) // By default, Selectable() is closing popup\n\t\t\t\tg.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_);\n\t\t\tSetCursorScreenPos(backup_pos);\n\t\t\tImVec4 previewing_ref_col;\n\t\t\tmemcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4));\n\t\t\tColorPicker4(\"##previewing_picker\", &previewing_ref_col.x, picker_flags);\n\t\t\tPopID();\n\t\t}\n\t\tPopItemWidth();\n\t}\n\tif (allow_opt_alpha_bar)\n\t{\n\t\tif (allow_opt_picker) Separator();\n\t\tCheckboxFlags(\"Alpha Bar\", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);\n\t}\n\tEndPopup();\n\tg.LockMarkEdited--;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: TreeNode, CollapsingHeader, etc.\n//-------------------------------------------------------------------------\n// - TreeNode()\n// - TreeNodeV()\n// - TreeNodeEx()\n// - TreeNodeExV()\n// - TreeNodeBehavior() [Internal]\n// - TreePush()\n// - TreePop()\n// - GetTreeNodeToLabelSpacing()\n// - SetNextItemOpen()\n// - CollapsingHeader()\n//-------------------------------------------------------------------------\n\nbool ImGui::TreeNode(const char* str_id, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tbool is_open = TreeNodeExV(str_id, 0, fmt, args);\n\tva_end(args);\n\treturn is_open;\n}\n\nbool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tbool is_open = TreeNodeExV(ptr_id, 0, fmt, args);\n\tva_end(args);\n\treturn is_open;\n}\n\nbool ImGui::TreeNode(const char* label)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\treturn TreeNodeBehavior(window->GetID(label), 0, label, NULL);\n}\n\nbool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)\n{\n\treturn TreeNodeExV(str_id, 0, fmt, args);\n}\n\nbool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)\n{\n\treturn TreeNodeExV(ptr_id, 0, fmt, args);\n}\n\nbool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\treturn TreeNodeBehavior(window->GetID(label), flags, label, NULL);\n}\n\nbool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tbool is_open = TreeNodeExV(str_id, flags, fmt, args);\n\tva_end(args);\n\treturn is_open;\n}\n\nbool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tbool is_open = TreeNodeExV(ptr_id, flags, fmt, args);\n\tva_end(args);\n\treturn is_open;\n}\n\nbool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst char* label, * label_end;\n\tImFormatStringToTempBufferV(&label, &label_end, fmt, args);\n\treturn TreeNodeBehavior(window->GetID(str_id), flags, label, label_end);\n}\n\nbool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst char* label, * label_end;\n\tImFormatStringToTempBufferV(&label, &label_end, fmt, args);\n\treturn TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end);\n}\n\nvoid ImGui::TreeNodeSetOpen(ImGuiID id, bool open)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiStorage* storage = g.CurrentWindow->DC.StateStorage;\n\tstorage->SetInt(id, open ? 1 : 0);\n}\n\nbool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)\n{\n\tif (flags & ImGuiTreeNodeFlags_Leaf)\n\t\treturn true;\n\n\t// We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function)\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tImGuiStorage* storage = window->DC.StateStorage;\n\n\tbool is_open;\n\tif (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen)\n\t{\n\t\tif (g.NextItemData.OpenCond & ImGuiCond_Always)\n\t\t{\n\t\t\tis_open = g.NextItemData.OpenVal;\n\t\t\tTreeNodeSetOpen(id, is_open);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.\n\t\t\tconst int stored_value = storage->GetInt(id, -1);\n\t\t\tif (stored_value == -1)\n\t\t\t{\n\t\t\t\tis_open = g.NextItemData.OpenVal;\n\t\t\t\tTreeNodeSetOpen(id, is_open);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tis_open = stored_value != 0;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tis_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;\n\t}\n\n\t// When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).\n\t// NB- If we are above max depth we still allow manually opened nodes to be logged.\n\tif (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand)\n\t\tis_open = true;\n\n\treturn is_open;\n}\n\nbool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;\n\tconst ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));\n\n\tif (!label_end)\n\t\tlabel_end = FindRenderedTextEnd(label);\n\tconst ImVec2 label_size = CalcTextSize(label, label_end, false);\n\n\t// We vertically grow up to current line height up the typical widget height.\n\tconst float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);\n\tImRect frame_bb;\n\tframe_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;\n\tframe_bb.Min.y = window->DC.CursorPos.y;\n\tframe_bb.Max.x = window->WorkRect.Max.x;\n\tframe_bb.Max.y = window->DC.CursorPos.y + frame_height;\n\tif (display_frame)\n\t{\n\t\t// Framed header expand a little outside the default padding, to the edge of InnerClipRect\n\t\t// (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f)\n\t\tframe_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f);\n\t\tframe_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f);\n\t}\n\n\tconst float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2);           // Collapser arrow width + Spacing\n\tconst float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset);                    // Latch before ItemSize changes it\n\tconst float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f);  // Include collapser\n\tImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);\n\tItemSize(ImVec2(text_width, frame_height), padding.y);\n\n\t// For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing\n\tImRect interact_bb = frame_bb;\n\tif (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)\n\t\tinteract_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;\n\n\t// Compute open and multi-select states before ItemAdd() as it clear NextItem data.\n\tbool is_open = TreeNodeUpdateNextOpen(id, flags);\n\tbool item_add = ItemAdd(interact_bb, id);\n\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;\n\tg.LastItemData.DisplayRect = frame_bb;\n\n\t// If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled:\n\t// Store data for the current depth to allow returning to this node from any child item.\n\t// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().\n\t// It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle.\n\t// Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase.\n\tif (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))\n\t\tif (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())\n\t\t{\n\t\t\tg.NavTreeNodeStack.resize(g.NavTreeNodeStack.Size + 1);\n\t\t\tImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();\n\t\t\tnav_tree_node_data->ID = id;\n\t\t\tnav_tree_node_data->InFlags = g.LastItemData.InFlags;\n\t\t\tnav_tree_node_data->NavRect = g.LastItemData.NavRect;\n\t\t\twindow->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);\n\t\t}\n\n\tconst bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;\n\tif (!item_add)\n\t{\n\t\tif (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))\n\t\t\tTreePushOverrideID(id);\n\t\tIMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));\n\t\treturn is_open;\n\t}\n\n\tImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;\n\tif ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap))\n\t\tbutton_flags |= ImGuiButtonFlags_AllowOverlap;\n\tif (!is_leaf)\n\t\tbutton_flags |= ImGuiButtonFlags_PressedOnDragDropHold;\n\n\t// We allow clicking on the arrow section with keyboard modifiers held, in order to easily\n\t// allow browsing a tree while preserving selection with code implementing multi-selection patterns.\n\t// When clicking on the rest of the tree node we always disallow keyboard modifiers.\n\tconst float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x;\n\tconst float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x;\n\tconst bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2);\n\tif (window != g.HoveredWindow || !is_mouse_x_over_arrow)\n\t\tbutton_flags |= ImGuiButtonFlags_NoKeyModifiers;\n\n\t// Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags.\n\t// Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support.\n\t// - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0)\n\t// - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=0)\n\t// - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1)\n\t// - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1)\n\t// - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0)\n\t// It is rather standard that arrow click react on Down rather than Up.\n\t// We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work.\n\tif (is_mouse_x_over_arrow)\n\t\tbutton_flags |= ImGuiButtonFlags_PressedOnClick;\n\telse if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)\n\t\tbutton_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;\n\telse\n\t\tbutton_flags |= ImGuiButtonFlags_PressedOnClickRelease;\n\n\tbool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0;\n\tconst bool was_selected = selected;\n\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);\n\tbool toggled = false;\n\tif (!is_leaf)\n\t{\n\t\tif (pressed && g.DragDropHoldJustPressedId != id)\n\t\t{\n\t\t\tif ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id))\n\t\t\t\ttoggled = true;\n\t\t\tif (flags & ImGuiTreeNodeFlags_OpenOnArrow)\n\t\t\t\ttoggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job\n\t\t\tif ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2)\n\t\t\t\ttoggled = true;\n\t\t}\n\t\telse if (pressed && g.DragDropHoldJustPressedId == id)\n\t\t{\n\t\t\tIM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold);\n\t\t\tif (!is_open) // When using Drag and Drop \"hold to open\" we keep the node highlighted after opening, but never close it again.\n\t\t\t\ttoggled = true;\n\t\t}\n\n\t\tif (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)\n\t\t{\n\t\t\ttoggled = true;\n\t\t\tNavClearPreferredPosForAxis(ImGuiAxis_X);\n\t\t\tNavMoveRequestCancel();\n\t\t}\n\t\tif (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?\n\t\t{\n\t\t\ttoggled = true;\n\t\t\tNavClearPreferredPosForAxis(ImGuiAxis_X);\n\t\t\tNavMoveRequestCancel();\n\t\t}\n\n\t\tif (toggled)\n\t\t{\n\t\t\tis_open = !is_open;\n\t\t\twindow->DC.StateStorage->SetInt(id, is_open);\n\t\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;\n\t\t}\n\t}\n\n\t// In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger.\n\tif (selected != was_selected) //-V547\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;\n\n\t// Render\n\tconst ImU32 text_col = GetColorU32(ImGuiCol_Text);\n\tImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin;\n\tif (display_frame)\n\t{\n\t\t// Framed type\n\t\tconst ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);\n\t\tRenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding);\n\t\tRenderNavHighlight(frame_bb, id, nav_highlight_flags);\n\t\tif (flags & ImGuiTreeNodeFlags_Bullet)\n\t\t\tRenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col);\n\t\telse if (!is_leaf)\n\t\t\tRenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f);\n\t\telse // Leaf without bullet, left-adjusted text\n\t\t\ttext_pos.x -= text_offset_x - padding.x;\n\t\tif (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)\n\t\t\tframe_bb.Max.x -= g.FontSize + style.FramePadding.x;\n\n\t\tif (g.LogEnabled)\n\t\t\tLogSetNextTextDecoration(\"###\", \"###\");\n\t\tRenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);\n\t}\n\telse\n\t{\n\t\t// Unframed typed for tree nodes\n\t\tif (hovered || selected)\n\t\t{\n\t\t\tconst ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);\n\t\t\tRenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);\n\t\t}\n\t\tRenderNavHighlight(frame_bb, id, nav_highlight_flags);\n\t\tif (flags & ImGuiTreeNodeFlags_Bullet)\n\t\t\tRenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col);\n\t\telse if (!is_leaf)\n\t\t\tRenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f);\n\t\tif (g.LogEnabled)\n\t\t\tLogSetNextTextDecoration(\">\", NULL);\n\t\tRenderText(text_pos, label, label_end, false);\n\t}\n\n\tif (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))\n\t\tTreePushOverrideID(id);\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));\n\treturn is_open;\n}\n\nvoid ImGui::TreePush(const char* str_id)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tIndent();\n\twindow->DC.TreeDepth++;\n\tPushID(str_id);\n}\n\nvoid ImGui::TreePush(const void* ptr_id)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tIndent();\n\twindow->DC.TreeDepth++;\n\tPushID(ptr_id);\n}\n\nvoid ImGui::TreePushOverrideID(ImGuiID id)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIndent();\n\twindow->DC.TreeDepth++;\n\tPushOverrideID(id);\n}\n\nvoid ImGui::TreePop()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tUnindent();\n\n\twindow->DC.TreeDepth--;\n\tImU32 tree_depth_mask = (1 << window->DC.TreeDepth);\n\n\t// Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)\n\tif (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request\n\t{\n\t\tImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();\n\t\tIM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());\n\t\tif (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())\n\t\t\tNavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, nav_tree_node_data);\n\t\tg.NavTreeNodeStack.pop_back();\n\t}\n\twindow->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1;\n\n\tIM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.\n\tPopID();\n}\n\n// Horizontal distance preceding label when using TreeNode() or Bullet()\nfloat ImGui::GetTreeNodeToLabelSpacing()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize + (g.Style.FramePadding.x * 2.0f);\n}\n\n// Set next TreeNode/CollapsingHeader open state.\nvoid ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.CurrentWindow->SkipItems)\n\t\treturn;\n\tg.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen;\n\tg.NextItemData.OpenVal = is_open;\n\tg.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always;\n}\n\n// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).\n// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode().\nbool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\treturn TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label);\n}\n\n// p_visible == NULL                        : regular collapsing header\n// p_visible != NULL && *p_visible == true  : show a small close button on the corner of the header, clicking the button will set *p_visible = false\n// p_visible != NULL && *p_visible == false : do not show the header at all\n// Do not mistake this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or ImGuiTreeNodeFlags_DefaultOpen.\nbool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tif (p_visible && !*p_visible)\n\t\treturn false;\n\n\tImGuiID id = window->GetID(label);\n\tflags |= ImGuiTreeNodeFlags_CollapsingHeader;\n\tif (p_visible)\n\t\tflags |= ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton;\n\tbool is_open = TreeNodeBehavior(id, flags, label);\n\tif (p_visible != NULL)\n\t{\n\t\t// Create a small overlapping close button\n\t\t// FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.\n\t\t// FIXME: CloseButton can overlap into text, need find a way to clip the text somehow.\n\t\tImGuiContext& g = *GImGui;\n\t\tImGuiLastItemData last_item_backup = g.LastItemData;\n\t\tfloat button_size = g.FontSize;\n\t\tfloat button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size);\n\t\tfloat button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y;\n\t\tImGuiID close_button_id = GetIDWithSeed(\"#CLOSE\", NULL, id);\n\t\tif (CloseButton(close_button_id, ImVec2(button_x, button_y)))\n\t\t\t*p_visible = false;\n\t\tg.LastItemData = last_item_backup;\n\t}\n\n\treturn is_open;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: Selectable\n//-------------------------------------------------------------------------\n// - Selectable()\n//-------------------------------------------------------------------------\n\n// Tip: pass a non-visible label (e.g. \"##hello\") then you can use the space to draw other text or image.\n// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id.\n// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags.\n// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported.\nbool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\n\t// Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle.\n\tImGuiID id = window->GetID(label);\n\tImVec2 label_size = CalcTextSize(label, NULL, true);\n\tImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);\n\tImVec2 pos = window->DC.CursorPos;\n\tpos.y += window->DC.CurrLineTextBaseOffset;\n\tItemSize(size, 0.0f);\n\n\t// Fill horizontal space\n\t// We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets.\n\tconst bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0;\n\tconst float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x;\n\tconst float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;\n\tif (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))\n\t\tsize.x = ImMax(label_size.x, max_x - min_x);\n\n\t// Text stays at the submission position, but bounding box may be extended on both sides\n\tconst ImVec2 text_min = pos;\n\tconst ImVec2 text_max(min_x + size.x, pos.y + size.y);\n\n\t// Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable.\n\tImRect bb(min_x, pos.y, text_max.x, text_max.y);\n\tif ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0)\n\t{\n\t\tconst float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;\n\t\tconst float spacing_y = style.ItemSpacing.y;\n\t\tconst float spacing_L = IM_FLOOR(spacing_x * 0.50f);\n\t\tconst float spacing_U = IM_FLOOR(spacing_y * 0.50f);\n\t\tbb.Min.x -= spacing_L;\n\t\tbb.Min.y -= spacing_U;\n\t\tbb.Max.x += (spacing_x - spacing_L);\n\t\tbb.Max.y += (spacing_y - spacing_U);\n\t}\n\t//if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); }\n\n\t// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable..\n\tconst float backup_clip_rect_min_x = window->ClipRect.Min.x;\n\tconst float backup_clip_rect_max_x = window->ClipRect.Max.x;\n\tif (span_all_columns)\n\t{\n\t\twindow->ClipRect.Min.x = window->ParentWorkRect.Min.x;\n\t\twindow->ClipRect.Max.x = window->ParentWorkRect.Max.x;\n\t}\n\n\tconst bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;\n\tconst bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None);\n\tif (span_all_columns)\n\t{\n\t\twindow->ClipRect.Min.x = backup_clip_rect_min_x;\n\t\twindow->ClipRect.Max.x = backup_clip_rect_max_x;\n\t}\n\n\tif (!item_add)\n\t\treturn false;\n\n\tconst bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;\n\tif (disabled_item && !disabled_global) // Only testing this as an optimization\n\t\tBeginDisabled();\n\n\t// FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only,\n\t// which would be advantageous since most selectable are not selected.\n\tif (span_all_columns && window->DC.CurrentColumns)\n\t\tPushColumnsBackground();\n\telse if (span_all_columns && g.CurrentTable)\n\t\tTablePushBackgroundChannel();\n\n\t// We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries\n\tImGuiButtonFlags button_flags = 0;\n\tif (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; }\n\tif (flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; }\n\tif (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }\n\tif (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }\n\tif (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }\n\tif ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }\n\n\tconst bool was_selected = selected;\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);\n\n\t// Auto-select when moved into\n\t// - This will be more fully fleshed in the range-select branch\n\t// - This is not exposed as it won't nicely work with some user side handling of shift/control\n\t// - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons\n\t//   - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope())\n\t//   - (2) usage will fail with clipped items\n\t//   The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.\n\tif ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId)\n\t\tif (g.NavJustMovedToId == id)\n\t\t\tselected = pressed = true;\n\n\t// Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard\n\tif (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover)))\n\t{\n\t\tif (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)\n\t\t{\n\t\t\tSetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect)\n\t\t\tg.NavDisableHighlight = true;\n\t\t}\n\t}\n\tif (pressed)\n\t\tMarkItemEdited(id);\n\n\t// In this branch, Selectable() cannot toggle the selection so this will never trigger.\n\tif (selected != was_selected) //-V547\n\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;\n\n\t// Render\n\tif (hovered || selected)\n\t{\n\t\tconst ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);\n\t\tRenderFrame(bb.Min, bb.Max, col, false, 0.0f);\n\t}\n\tif (g.NavId == id)\n\t\tRenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);\n\n\tif (span_all_columns && window->DC.CurrentColumns)\n\t\tPopColumnsBackground();\n\telse if (span_all_columns && g.CurrentTable)\n\t\tTablePopBackgroundChannel();\n\n\tRenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);\n\n\t// Automatically close popups\n\tif (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup))\n\t\tCloseCurrentPopup();\n\n\tif (disabled_item && !disabled_global)\n\t\tEndDisabled();\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);\n\treturn pressed; //-V1020\n}\n\nbool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)\n{\n\tif (Selectable(label, *p_selected, flags, size_arg))\n\t{\n\t\t*p_selected = !*p_selected;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: ListBox\n//-------------------------------------------------------------------------\n// - BeginListBox()\n// - EndListBox()\n// - ListBox()\n//-------------------------------------------------------------------------\n\n// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. \"##empty\"\n// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height).\nbool ImGui::BeginListBox(const char* label, const ImVec2& size_arg)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = GetID(label);\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\t// Size default to hold ~7.25 items.\n\t// Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.\n\tImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f));\n\tImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));\n\tImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);\n\tImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));\n\tg.NextItemData.ClearFlags();\n\n\tif (!IsRectVisible(bb.Min, bb.Max))\n\t{\n\t\tItemSize(bb.GetSize(), style.FramePadding.y);\n\t\tItemAdd(bb, 0, &frame_bb);\n\t\treturn false;\n\t}\n\n\t// FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well.\n\tBeginGroup();\n\tif (label_size.x > 0.0f)\n\t{\n\t\tImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y);\n\t\tRenderText(label_pos, label);\n\t\twindow->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size);\n\t}\n\n\tBeginChildFrame(id, frame_bb.GetSize());\n\treturn true;\n}\n\nvoid ImGui::EndListBox()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && \"Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?\");\n\tIM_UNUSED(window);\n\n\tEndChildFrame();\n\tEndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label\n}\n\nbool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items)\n{\n\tconst bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);\n\treturn value_changed;\n}\n\n// This is merely a helper around BeginListBox(), EndListBox().\n// Considering using those directly to submit custom data or store selection differently.\nbool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)\n{\n\tImGuiContext& g = *GImGui;\n\n\t// Calculate size from \"height_in_items\"\n\tif (height_in_items < 0)\n\t\theight_in_items = ImMin(items_count, 7);\n\tfloat height_in_items_f = height_in_items + 0.25f;\n\tImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f));\n\n\tif (!BeginListBox(label, size))\n\t\treturn false;\n\n\t// Assume all items have even height (= 1 line of text). If you need items of different height,\n\t// you can create a custom version of ListBox() in your code without using the clipper.\n\tbool value_changed = false;\n\tImGuiListClipper clipper;\n\tclipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to.\n\twhile (clipper.Step())\n\t\tfor (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)\n\t\t{\n\t\t\tconst char* item_text;\n\t\t\tif (!items_getter(data, i, &item_text))\n\t\t\t\titem_text = \"*Unknown item*\";\n\n\t\t\tPushID(i);\n\t\t\tconst bool item_selected = (i == *current_item);\n\t\t\tif (Selectable(item_text, item_selected))\n\t\t\t{\n\t\t\t\t*current_item = i;\n\t\t\t\tvalue_changed = true;\n\t\t\t}\n\t\t\tif (item_selected)\n\t\t\t\tSetItemDefaultFocus();\n\t\t\tPopID();\n\t\t}\n\tEndListBox();\n\n\tif (value_changed)\n\t\tMarkItemEdited(g.LastItemData.ID);\n\n\treturn value_changed;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: PlotLines, PlotHistogram\n//-------------------------------------------------------------------------\n// - PlotEx() [Internal]\n// - PlotLines()\n// - PlotHistogram()\n//-------------------------------------------------------------------------\n// Plot/Graph widgets are not very good.\n// Consider writing your own, or using a third-party one, see:\n// - ImPlot https://github.com/epezent/implot\n// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions\n//-------------------------------------------------------------------------\n\nint ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn -1;\n\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\n\tconst ImVec2 label_size = CalcTextSize(label, NULL, true);\n\tconst ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);\n\n\tconst ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);\n\tconst ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);\n\tconst ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));\n\tItemSize(total_bb, style.FramePadding.y);\n\tif (!ItemAdd(total_bb, 0, &frame_bb))\n\t\treturn -1;\n\tconst bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);\n\n\t// Determine scale from values if not specified\n\tif (scale_min == FLT_MAX || scale_max == FLT_MAX)\n\t{\n\t\tfloat v_min = FLT_MAX;\n\t\tfloat v_max = -FLT_MAX;\n\t\tfor (int i = 0; i < values_count; i++)\n\t\t{\n\t\t\tconst float v = values_getter(data, i);\n\t\t\tif (v != v) // Ignore NaN values\n\t\t\t\tcontinue;\n\t\t\tv_min = ImMin(v_min, v);\n\t\t\tv_max = ImMax(v_max, v);\n\t\t}\n\t\tif (scale_min == FLT_MAX)\n\t\t\tscale_min = v_min;\n\t\tif (scale_max == FLT_MAX)\n\t\t\tscale_max = v_max;\n\t}\n\n\tRenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);\n\n\tconst int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1;\n\tint idx_hovered = -1;\n\tif (values_count >= values_count_min)\n\t{\n\t\tint res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);\n\t\tint item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);\n\n\t\t// Tooltip on hover\n\t\tif (hovered && inner_bb.Contains(g.IO.MousePos))\n\t\t{\n\t\t\tconst float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);\n\t\t\tconst int v_idx = (int)(t * item_count);\n\t\t\tIM_ASSERT(v_idx >= 0 && v_idx < values_count);\n\n\t\t\tconst float v0 = values_getter(data, (v_idx + values_offset) % values_count);\n\t\t\tconst float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);\n\t\t\tif (plot_type == ImGuiPlotType_Lines)\n\t\t\t\tSetTooltip(\"%d: %8.4g\\n%d: %8.4g\", v_idx, v0, v_idx + 1, v1);\n\t\t\telse if (plot_type == ImGuiPlotType_Histogram)\n\t\t\t\tSetTooltip(\"%d: %8.4g\", v_idx, v0);\n\t\t\tidx_hovered = v_idx;\n\t\t}\n\n\t\tconst float t_step = 1.0f / (float)res_w;\n\t\tconst float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min));\n\n\t\tfloat v0 = values_getter(data, (0 + values_offset) % values_count);\n\t\tfloat t0 = 0.0f;\n\t\tImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale));                       // Point in the normalized space of our target rectangle\n\t\tfloat histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f);   // Where does the zero line stands\n\n\t\tconst ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);\n\t\tconst ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered);\n\n\t\tfor (int n = 0; n < res_w; n++)\n\t\t{\n\t\t\tconst float t1 = t0 + t_step;\n\t\t\tconst int v1_idx = (int)(t0 * item_count + 0.5f);\n\t\t\tIM_ASSERT(v1_idx >= 0 && v1_idx < values_count);\n\t\t\tconst float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);\n\t\t\tconst ImVec2 tp1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale));\n\n\t\t\t// NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU.\n\t\t\tImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);\n\t\t\tImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));\n\t\t\tif (plot_type == ImGuiPlotType_Lines)\n\t\t\t{\n\t\t\t\twindow->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);\n\t\t\t}\n\t\t\telse if (plot_type == ImGuiPlotType_Histogram)\n\t\t\t{\n\t\t\t\tif (pos1.x >= pos0.x + 2.0f)\n\t\t\t\t\tpos1.x -= 1.0f;\n\t\t\t\twindow->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);\n\t\t\t}\n\n\t\t\tt0 = t1;\n\t\t\ttp0 = tp1;\n\t\t}\n\t}\n\n\t// Text overlay\n\tif (overlay_text)\n\t\tRenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f));\n\n\tif (label_size.x > 0.0f)\n\t\tRenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);\n\n\t// Return hovered index or -1 if none are hovered.\n\t// This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx().\n\treturn idx_hovered;\n}\n\nstruct ImGuiPlotArrayGetterData\n{\n\tconst float* Values;\n\tint Stride;\n\n\tImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; }\n};\n\nstatic float Plot_ArrayGetter(void* data, int idx)\n{\n\tImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data;\n\tconst float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);\n\treturn v;\n}\n\nvoid ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)\n{\n\tImGuiPlotArrayGetterData data(values, stride);\n\tPlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);\n}\n\nvoid ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)\n{\n\tPlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);\n}\n\nvoid ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)\n{\n\tImGuiPlotArrayGetterData data(values, stride);\n\tPlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);\n}\n\nvoid ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)\n{\n\tPlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: Value helpers\n// Those is not very useful, legacy API.\n//-------------------------------------------------------------------------\n// - Value()\n//-------------------------------------------------------------------------\n\nvoid ImGui::Value(const char* prefix, bool b)\n{\n\tText(\"%s: %s\", prefix, (b ? \"true\" : \"false\"));\n}\n\nvoid ImGui::Value(const char* prefix, int v)\n{\n\tText(\"%s: %d\", prefix, v);\n}\n\nvoid ImGui::Value(const char* prefix, unsigned int v)\n{\n\tText(\"%s: %d\", prefix, v);\n}\n\nvoid ImGui::Value(const char* prefix, float v, const char* float_format)\n{\n\tif (float_format)\n\t{\n\t\tchar fmt[64];\n\t\tImFormatString(fmt, IM_ARRAYSIZE(fmt), \"%%s: %s\", float_format);\n\t\tText(fmt, prefix, v);\n\t}\n\telse\n\t{\n\t\tText(\"%s: %.3f\", prefix, v);\n\t}\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] MenuItem, BeginMenu, EndMenu, etc.\n//-------------------------------------------------------------------------\n// - ImGuiMenuColumns [Internal]\n// - BeginMenuBar()\n// - EndMenuBar()\n// - BeginMainMenuBar()\n// - EndMainMenuBar()\n// - BeginMenu()\n// - EndMenu()\n// - MenuItemEx() [Internal]\n// - MenuItem()\n//-------------------------------------------------------------------------\n\n// Helpers for internal use\nvoid ImGuiMenuColumns::Update(float spacing, bool window_reappearing)\n{\n\tif (window_reappearing)\n\t\tmemset(Widths, 0, sizeof(Widths));\n\tSpacing = (ImU16)spacing;\n\tCalcNextTotalWidth(true);\n\tmemset(Widths, 0, sizeof(Widths));\n\tTotalWidth = NextTotalWidth;\n\tNextTotalWidth = 0;\n}\n\nvoid ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets)\n{\n\tImU16 offset = 0;\n\tbool want_spacing = false;\n\tfor (int i = 0; i < IM_ARRAYSIZE(Widths); i++)\n\t{\n\t\tImU16 width = Widths[i];\n\t\tif (want_spacing && width > 0)\n\t\t\toffset += Spacing;\n\t\twant_spacing |= (width > 0);\n\t\tif (update_offsets)\n\t\t{\n\t\t\tif (i == 1) { OffsetLabel = offset; }\n\t\t\tif (i == 2) { OffsetShortcut = offset; }\n\t\t\tif (i == 3) { OffsetMark = offset; }\n\t\t}\n\t\toffset += width;\n\t}\n\tNextTotalWidth = offset;\n}\n\nfloat ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark)\n{\n\tWidths[0] = ImMax(Widths[0], (ImU16)w_icon);\n\tWidths[1] = ImMax(Widths[1], (ImU16)w_label);\n\tWidths[2] = ImMax(Widths[2], (ImU16)w_shortcut);\n\tWidths[3] = ImMax(Widths[3], (ImU16)w_mark);\n\tCalcNextTotalWidth(false);\n\treturn (float)ImMax(TotalWidth, NextTotalWidth);\n}\n\n// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere..\n// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer.\n// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary.\n// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars.\nbool ImGui::BeginMenuBar()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\tif (!(window->Flags & ImGuiWindowFlags_MenuBar))\n\t\treturn false;\n\n\tIM_ASSERT(!window->DC.MenuBarAppending);\n\tBeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore\n\tPushID(\"##menubar\");\n\n\t// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.\n\t// We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.\n\tImRect bar_rect = window->MenuBarRect();\n\tImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y));\n\tclip_rect.ClipWith(window->OuterRectClipped);\n\tPushClipRect(clip_rect.Min, clip_rect.Max, false);\n\n\t// We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags).\n\twindow->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y);\n\twindow->DC.LayoutType = ImGuiLayoutType_Horizontal;\n\twindow->DC.IsSameLine = false;\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Menu;\n\twindow->DC.MenuBarAppending = true;\n\tAlignTextToFramePadding();\n\treturn true;\n}\n\nvoid ImGui::EndMenuBar()\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\tImGuiContext& g = *GImGui;\n\n\t// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.\n\tif (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))\n\t{\n\t\t// Try to find out if the request is for one of our child menu\n\t\tImGuiWindow* nav_earliest_child = g.NavWindow;\n\t\twhile (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))\n\t\t\tnav_earliest_child = nav_earliest_child->ParentWindow;\n\t\tif (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0)\n\t\t{\n\t\t\t// To do so we claim focus back, restore NavId and then process the movement request for yet another frame.\n\t\t\t// This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering)\n\t\t\tconst ImGuiNavLayer layer = ImGuiNavLayer_Menu;\n\t\t\tIM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary)\n\t\t\tFocusWindow(window);\n\t\t\tSetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);\n\t\t\tg.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.\n\t\t\tg.NavDisableMouseHover = g.NavMousePosDirty = true;\n\t\t\tNavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat\n\t\t}\n\t}\n\n\tIM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive \"warning C6011: Dereferencing NULL pointer 'window'\"\n\tIM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar);\n\tIM_ASSERT(window->DC.MenuBarAppending);\n\tPopClipRect();\n\tPopID();\n\twindow->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.\n\tg.GroupStack.back().EmitItem = false;\n\tEndGroup(); // Restore position on layer 0\n\twindow->DC.LayoutType = ImGuiLayoutType_Vertical;\n\twindow->DC.IsSameLine = false;\n\twindow->DC.NavLayerCurrent = ImGuiNavLayer_Main;\n\twindow->DC.MenuBarAppending = false;\n}\n\n// Important: calling order matters!\n// FIXME: Somehow overlapping with docking tech.\n// FIXME: The \"rect-cut\" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts)\nbool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags)\n{\n\tIM_ASSERT(dir != ImGuiDir_None);\n\n\tImGuiWindow* bar_window = FindWindowByName(name);\n\tif (bar_window == NULL || bar_window->BeginCount == 0)\n\t{\n\t\t// Calculate and set window size/position\n\t\tImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());\n\t\tImRect avail_rect = viewport->GetBuildWorkRect();\n\t\tImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;\n\t\tImVec2 pos = avail_rect.Min;\n\t\tif (dir == ImGuiDir_Right || dir == ImGuiDir_Down)\n\t\t\tpos[axis] = avail_rect.Max[axis] - axis_size;\n\t\tImVec2 size = avail_rect.GetSize();\n\t\tsize[axis] = axis_size;\n\t\tSetNextWindowPos(pos);\n\t\tSetNextWindowSize(size);\n\n\t\t// Report our size into work area (for next frame) using actual window size\n\t\tif (dir == ImGuiDir_Up || dir == ImGuiDir_Left)\n\t\t\tviewport->BuildWorkOffsetMin[axis] += axis_size;\n\t\telse if (dir == ImGuiDir_Down || dir == ImGuiDir_Right)\n\t\t\tviewport->BuildWorkOffsetMax[axis] -= axis_size;\n\t}\n\n\twindow_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;\n\tPushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);\n\tPushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint\n\tbool is_open = Begin(name, NULL, window_flags);\n\tPopStyleVar(2);\n\n\treturn is_open;\n}\n\nbool ImGui::BeginMainMenuBar()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();\n\n\t// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.\n\t// FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea?\n\t// FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings.\n\tg.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));\n\tImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;\n\tfloat height = GetFrameHeight();\n\tbool is_open = BeginViewportSideBar(\"##MainMenuBar\", viewport, ImGuiDir_Up, height, window_flags);\n\tg.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);\n\n\tif (is_open)\n\t\tBeginMenuBar();\n\telse\n\t\tEnd();\n\treturn is_open;\n}\n\nvoid ImGui::EndMainMenuBar()\n{\n\tEndMenuBar();\n\n\t// When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window\n\t// FIXME: With this strategy we won't be able to restore a NULL focus.\n\tImGuiContext& g = *GImGui;\n\tif (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest)\n\t\tFocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild);\n\n\tEnd();\n}\n\nstatic bool IsRootOfOpenMenuSet()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu))\n\t\treturn false;\n\n\t// Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others\n\t// (e.g. inside menu bar vs loose menu items) based on parent ID.\n\t// This would however prevent the use of e.g. PushID() user code submitting menus.\n\t// Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag,\n\t// making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.\n\t// Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup\n\t// doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu.\n\t// In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer.\n\t// This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still\n\t// open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart\n\t// it likely won't be a problem anyone runs into.\n\tconst ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];\n\tif (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)\n\t\treturn false;\n\treturn upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true);\n}\n\nbool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = window->GetID(label);\n\tbool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);\n\n\t// Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)\n\t// The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation.\n\tImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;\n\tif (window->Flags & ImGuiWindowFlags_ChildMenu)\n\t\twindow_flags |= ImGuiWindowFlags_ChildWindow;\n\n\t// If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin().\n\t// We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame.\n\t// If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used.\n\tif (g.MenusIdSubmittedThisFrame.contains(id))\n\t{\n\t\tif (menu_is_open)\n\t\t\tmenu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)\n\t\telse\n\t\t\tg.NextWindowData.ClearFlags();          // we behave like Begin() and need to consume those values\n\t\treturn menu_is_open;\n\t}\n\n\t// Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu\n\tg.MenusIdSubmittedThisFrame.push_back(id);\n\n\tImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\t// Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window)\n\t// This is only done for items for the menu set and not the full parent window.\n\tconst bool menuset_is_open = IsRootOfOpenMenuSet();\n\tif (menuset_is_open)\n\t\tPushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true);\n\n\t// The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu,\n\t// However the final position is going to be different! It is chosen by FindBestWindowPosForPopup().\n\t// e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering.\n\tImVec2 popup_pos, pos = window->DC.CursorPos;\n\tPushID(label);\n\tif (!enabled)\n\t\tBeginDisabled();\n\tconst ImGuiMenuColumns* offsets = &window->DC.MenuColumns;\n\tbool pressed;\n\n\t// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.\n\tconst ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups;\n\tif (window->DC.LayoutType == ImGuiLayoutType_Horizontal)\n\t{\n\t\t// Menu inside an horizontal menu bar\n\t\t// Selectable extend their highlight by half ItemSpacing in each direction.\n\t\t// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()\n\t\tpopup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight());\n\t\twindow->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f);\n\t\tPushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));\n\t\tfloat w = label_size.x;\n\t\tImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);\n\t\tpressed = Selectable(\"\", menu_is_open, selectable_flags, ImVec2(w, label_size.y));\n\t\tRenderText(text_pos, label);\n\t\tPopStyleVar();\n\t\twindow->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().\n\t}\n\telse\n\t{\n\t\t// Menu inside a regular/vertical menu\n\t\t// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.\n\t\t//  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.\n\t\tpopup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);\n\t\tfloat icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;\n\t\tfloat checkmark_w = IM_FLOOR(g.FontSize * 1.20f);\n\t\tfloat min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame\n\t\tfloat extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);\n\t\tImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);\n\t\tpressed = Selectable(\"\", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));\n\t\tRenderText(text_pos, label);\n\t\tif (icon_w > 0.0f)\n\t\t\tRenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);\n\t\tRenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);\n\t}\n\tif (!enabled)\n\t\tEndDisabled();\n\n\tconst bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover;\n\tif (menuset_is_open)\n\t\tPopItemFlag();\n\n\tbool want_open = false;\n\tbool want_close = false;\n\tif (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))\n\t{\n\t\t// Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu\n\t\t// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.\n\t\tbool moving_toward_child_menu = false;\n\t\tImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below)\n\t\tImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL;\n\t\tif (g.HoveredWindow == window && child_menu_window != NULL)\n\t\t{\n\t\t\tfloat ref_unit = g.FontSize; // FIXME-DPI\n\t\t\tfloat child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f;\n\t\t\tImRect next_window_rect = child_menu_window->Rect();\n\t\t\tImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta);\n\t\t\tImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR();\n\t\t\tImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR();\n\t\t\tfloat extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f);   // add a bit of extra slack.\n\t\t\tta.x += child_dir * -0.5f;\n\t\t\ttb.x += child_dir * ref_unit;\n\t\t\ttc.x += child_dir * ref_unit;\n\t\t\ttb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f);                           // triangle has maximum height to limit the slope and the bias toward large sub-menus\n\t\t\ttc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f);\n\t\t\tmoving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);\n\t\t\t//GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]\n\t\t}\n\n\t\t// The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not)\n\t\t// But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon.\n\t\t// (Remember to test this on BeginPopup(\"A\")->BeginMenu(\"B\") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.)\n\t\tif (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover)\n\t\t\twant_close = true;\n\n\t\t// Open\n\t\tif (!menu_is_open && pressed) // Click/activate to open\n\t\t\twant_open = true;\n\t\telse if (!menu_is_open && hovered && !moving_toward_child_menu) // Hover to open\n\t\t\twant_open = true;\n\t\tif (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open\n\t\t{\n\t\t\twant_open = true;\n\t\t\tNavMoveRequestCancel();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Menu bar\n\t\tif (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it\n\t\t{\n\t\t\twant_close = true;\n\t\t\twant_open = menu_is_open = false;\n\t\t}\n\t\telse if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others\n\t\t{\n\t\t\twant_open = true;\n\t\t}\n\t\telse if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open\n\t\t{\n\t\t\twant_open = true;\n\t\t\tNavMoveRequestCancel();\n\t\t}\n\t}\n\n\tif (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu(\"options\", has_object)) { ..use object.. }'\n\t\twant_close = true;\n\tif (want_close && IsPopupOpen(id, ImGuiPopupFlags_None))\n\t\tClosePopupToLevel(g.BeginPopupStack.Size, true);\n\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));\n\tPopID();\n\n\tif (want_open && !menu_is_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)\n\t{\n\t\t// Don't reopen/recycle same menu level in the same frame, first close the other menu and yield for a frame.\n\t\tOpenPopup(label);\n\t}\n\telse if (want_open)\n\t{\n\t\tmenu_is_open = true;\n\t\tOpenPopup(label);\n\t}\n\n\tif (menu_is_open)\n\t{\n\t\tImGuiLastItemData last_item_in_parent = g.LastItemData;\n\t\tSetNextWindowPos(popup_pos, ImGuiCond_Always);                  // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos.\n\t\tPushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding\n\t\tmenu_is_open = BeginPopupEx(id, window_flags);                  // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)\n\t\tPopStyleVar();\n\t\tif (menu_is_open)\n\t\t{\n\t\t\t// Restore LastItemData so IsItemXXXX functions can work after BeginMenu()/EndMenu()\n\t\t\t// (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for ImGuiItemFlags_NoWindowHoverableCheck)\n\t\t\tg.LastItemData = last_item_in_parent;\n\t\t\tif (g.HoveredWindow == window)\n\t\t\t\tg.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;\n\t\t}\n\t}\n\telse\n\t{\n\t\tg.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values\n\t}\n\n\treturn menu_is_open;\n}\n\nbool ImGui::BeginMenu(const char* label, bool enabled)\n{\n\treturn BeginMenuEx(label, NULL, enabled);\n}\n\nvoid ImGui::EndMenu()\n{\n\t// Nav: When a left move request our menu failed, close ourselves.\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tIM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginMenu()/EndMenu() calls\n\tImGuiWindow* parent_window = window->ParentWindow;  // Should always be != NULL is we passed assert.\n\tif (window->BeginCount == window->BeginCountPreviousFrame)\n\t\tif (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet())\n\t\t\tif (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical)\n\t\t\t{\n\t\t\t\tClosePopupToLevel(g.BeginPopupStack.Size - 1, true);\n\t\t\t\tNavMoveRequestCancel();\n\t\t\t}\n\n\tEndPopup();\n}\n\nbool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled)\n{\n\tImGuiWindow* window = GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tImGuiStyle& style = g.Style;\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\t// See BeginMenuEx() for comments about this.\n\tconst bool menuset_is_open = IsRootOfOpenMenuSet();\n\tif (menuset_is_open)\n\t\tPushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true);\n\n\t// We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73),\n\t// but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only.\n\tbool pressed;\n\tPushID(label);\n\tif (!enabled)\n\t\tBeginDisabled();\n\n\t// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.\n\tconst ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;\n\tconst ImGuiMenuColumns* offsets = &window->DC.MenuColumns;\n\tif (window->DC.LayoutType == ImGuiLayoutType_Horizontal)\n\t{\n\t\t// Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful\n\t\t// Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark.\n\t\tfloat w = label_size.x;\n\t\twindow->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f);\n\t\tImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);\n\t\tPushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));\n\t\tpressed = Selectable(\"\", selected, selectable_flags, ImVec2(w, 0.0f));\n\t\tPopStyleVar();\n\t\tif (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)\n\t\t\tRenderText(text_pos, label);\n\t\twindow->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().\n\t}\n\telse\n\t{\n\t\t// Menu item inside a vertical menu\n\t\t// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.\n\t\t//  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.\n\t\tfloat icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;\n\t\tfloat shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f;\n\t\tfloat checkmark_w = IM_FLOOR(g.FontSize * 1.20f);\n\t\tfloat min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame\n\t\tfloat stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);\n\t\tpressed = Selectable(\"\", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));\n\t\tif (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)\n\t\t{\n\t\t\tRenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label);\n\t\t\tif (icon_w > 0.0f)\n\t\t\t\tRenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);\n\t\t\tif (shortcut_w > 0.0f)\n\t\t\t{\n\t\t\t\tPushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);\n\t\t\t\tRenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false);\n\t\t\t\tPopStyleColor();\n\t\t\t}\n\t\t\tif (selected)\n\t\t\t\tRenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);\n\t\t}\n\t}\n\tIMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));\n\tif (!enabled)\n\t\tEndDisabled();\n\tPopID();\n\tif (menuset_is_open)\n\t\tPopItemFlag();\n\n\treturn pressed;\n}\n\nbool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)\n{\n\treturn MenuItemEx(label, NULL, shortcut, selected, enabled);\n}\n\nbool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)\n{\n\tif (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled))\n\t{\n\t\tif (p_selected)\n\t\t\t*p_selected = !*p_selected;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.\n//-------------------------------------------------------------------------\n// - BeginTabBar()\n// - BeginTabBarEx() [Internal]\n// - EndTabBar()\n// - TabBarLayout() [Internal]\n// - TabBarCalcTabID() [Internal]\n// - TabBarCalcMaxTabWidth() [Internal]\n// - TabBarFindTabById() [Internal]\n// - TabBarFindTabByOrder() [Internal]\n// - TabBarGetCurrentTab() [Internal]\n// - TabBarGetTabName() [Internal]\n// - TabBarRemoveTab() [Internal]\n// - TabBarCloseTab() [Internal]\n// - TabBarScrollClamp() [Internal]\n// - TabBarScrollToTab() [Internal]\n// - TabBarQueueFocus() [Internal]\n// - TabBarQueueReorder() [Internal]\n// - TabBarProcessReorderFromMousePos() [Internal]\n// - TabBarProcessReorder() [Internal]\n// - TabBarScrollingButtons() [Internal]\n// - TabBarTabListPopupButton() [Internal]\n//-------------------------------------------------------------------------\n\nstruct ImGuiTabBarSection\n{\n\tint                 TabCount;               // Number of tabs in this section.\n\tfloat               Width;                  // Sum of width of tabs in this section (after shrinking down)\n\tfloat               Spacing;                // Horizontal spacing at the end of the section.\n\n\tImGuiTabBarSection() { memset(this, 0, sizeof(*this)); }\n};\n\nnamespace ImGui\n{\n\tstatic void             TabBarLayout(ImGuiTabBar* tab_bar);\n\tstatic ImU32            TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window);\n\tstatic float            TabBarCalcMaxTabWidth();\n\tstatic float            TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);\n\tstatic void             TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections);\n\tstatic ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);\n\tstatic ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);\n}\n\nImGuiTabBar::ImGuiTabBar()\n{\n\tmemset(this, 0, sizeof(*this));\n\tCurrFrameVisible = PrevFrameVisible = -1;\n\tLastTabItemIdx = -1;\n}\n\nstatic inline int TabItemGetSectionIdx(const ImGuiTabItem* tab)\n{\n\treturn (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;\n}\n\nstatic int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs)\n{\n\tconst ImGuiTabItem* a = (const ImGuiTabItem*)lhs;\n\tconst ImGuiTabItem* b = (const ImGuiTabItem*)rhs;\n\tconst int a_section = TabItemGetSectionIdx(a);\n\tconst int b_section = TabItemGetSectionIdx(b);\n\tif (a_section != b_section)\n\t\treturn a_section - b_section;\n\treturn (int)(a->IndexDuringLayout - b->IndexDuringLayout);\n}\n\nstatic int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs)\n{\n\tconst ImGuiTabItem* a = (const ImGuiTabItem*)lhs;\n\tconst ImGuiTabItem* b = (const ImGuiTabItem*)rhs;\n\treturn (int)(a->BeginOrder - b->BeginOrder);\n}\n\nstatic ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref)\n{\n\tImGuiContext& g = *GImGui;\n\treturn ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index);\n}\n\nstatic ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)\n{\n\tImGuiContext& g = *GImGui;\n\tif (g.TabBars.Contains(tab_bar))\n\t\treturn ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar));\n\treturn ImGuiPtrOrIndex(tab_bar);\n}\n\nbool    ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiID id = window->GetID(str_id);\n\tImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id);\n\tImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);\n\ttab_bar->ID = id;\n\treturn BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused);\n}\n\nbool    ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tif ((flags & ImGuiTabBarFlags_DockNode) == 0)\n\t\tPushOverrideID(tab_bar->ID);\n\n\t// Add to stack\n\tg.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar));\n\tg.CurrentTabBar = tab_bar;\n\n\t// Append with multiple BeginTabBar()/EndTabBar() pairs.\n\ttab_bar->BackupCursorPos = window->DC.CursorPos;\n\tif (tab_bar->CurrFrameVisible == g.FrameCount)\n\t{\n\t\twindow->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY);\n\t\ttab_bar->BeginCount++;\n\t\treturn true;\n\t}\n\n\t// Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable\n\tif ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))\n\t\tImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);\n\ttab_bar->TabsAddedNew = false;\n\n\t// Flags\n\tif ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)\n\t\tflags |= ImGuiTabBarFlags_FittingPolicyDefault_;\n\n\ttab_bar->Flags = flags;\n\ttab_bar->BarRect = tab_bar_bb;\n\ttab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab()\n\ttab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible;\n\ttab_bar->CurrFrameVisible = g.FrameCount;\n\ttab_bar->PrevTabsContentsHeight = tab_bar->CurrTabsContentsHeight;\n\ttab_bar->CurrTabsContentsHeight = 0.0f;\n\ttab_bar->ItemSpacingY = g.Style.ItemSpacing.y;\n\ttab_bar->FramePadding = g.Style.FramePadding;\n\ttab_bar->TabsActiveCount = 0;\n\ttab_bar->LastTabItemIdx = -1;\n\ttab_bar->BeginCount = 1;\n\n\t// Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap\n\twindow->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY);\n\n\t// Draw separator\n\tconst ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);\n\tconst float y = tab_bar->BarRect.Max.y - 1.0f;\n\t{\n\t\tconst float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f);\n\t\tconst float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f);\n\t\twindow->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);\n\t}\n\treturn true;\n}\n\nvoid    ImGui::EndTabBar()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiTabBar* tab_bar = g.CurrentTabBar;\n\tif (tab_bar == NULL)\n\t{\n\t\tIM_ASSERT_USER_ERROR(tab_bar != NULL, \"Mismatched BeginTabBar()/EndTabBar()!\");\n\t\treturn;\n\t}\n\n\t// Fallback in case no TabItem have been submitted\n\tif (tab_bar->WantLayout)\n\t\tTabBarLayout(tab_bar);\n\n\t// Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed().\n\tconst bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);\n\tif (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing)\n\t{\n\t\ttab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight);\n\t\twindow->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight;\n\t}\n\telse\n\t{\n\t\twindow->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->PrevTabsContentsHeight;\n\t}\n\tif (tab_bar->BeginCount > 1)\n\t\twindow->DC.CursorPos = tab_bar->BackupCursorPos;\n\n\ttab_bar->LastTabItemIdx = -1;\n\tif ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)\n\t\tPopID();\n\n\tg.CurrentTabBarStack.pop_back();\n\tg.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back());\n}\n\n// Scrolling happens only in the central section (leading/trailing sections are not scrolling)\nstatic float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections)\n{\n\treturn tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing;\n}\n\n// This is called only once a frame before by the first call to ItemTab()\n// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions.\nstatic void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)\n{\n\tImGuiContext& g = *GImGui;\n\ttab_bar->WantLayout = false;\n\n\t// Garbage collect by compacting list\n\t// Detect if we need to sort out tab list (e.g. in rare case where a tab changed section)\n\tint tab_dst_n = 0;\n\tbool need_sort_by_section = false;\n\tImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing\n\tfor (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)\n\t{\n\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];\n\t\tif (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose)\n\t\t{\n\t\t\t// Remove tab\n\t\t\tif (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; }\n\t\t\tif (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; }\n\t\t\tif (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; }\n\t\t\tcontinue;\n\t\t}\n\t\tif (tab_dst_n != tab_src_n)\n\t\t\ttab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n];\n\n\t\ttab = &tab_bar->Tabs[tab_dst_n];\n\t\ttab->IndexDuringLayout = (ImS16)tab_dst_n;\n\n\t\t// We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another)\n\t\tint curr_tab_section_n = TabItemGetSectionIdx(tab);\n\t\tif (tab_dst_n > 0)\n\t\t{\n\t\t\tImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1];\n\t\t\tint prev_tab_section_n = TabItemGetSectionIdx(prev_tab);\n\t\t\tif (curr_tab_section_n == 0 && prev_tab_section_n != 0)\n\t\t\t\tneed_sort_by_section = true;\n\t\t\tif (prev_tab_section_n == 2 && curr_tab_section_n != 2)\n\t\t\t\tneed_sort_by_section = true;\n\t\t}\n\n\t\tsections[curr_tab_section_n].TabCount++;\n\t\ttab_dst_n++;\n\t}\n\tif (tab_bar->Tabs.Size != tab_dst_n)\n\t\ttab_bar->Tabs.resize(tab_dst_n);\n\n\tif (need_sort_by_section)\n\t\tImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection);\n\n\t// Calculate spacing between sections\n\tsections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;\n\tsections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;\n\n\t// Setup next selected tab\n\tImGuiID scroll_to_tab_id = 0;\n\tif (tab_bar->NextSelectedTabId)\n\t{\n\t\ttab_bar->SelectedTabId = tab_bar->NextSelectedTabId;\n\t\ttab_bar->NextSelectedTabId = 0;\n\t\tscroll_to_tab_id = tab_bar->SelectedTabId;\n\t}\n\n\t// Process order change request (we could probably process it when requested but it's just saner to do it in a single spot).\n\tif (tab_bar->ReorderRequestTabId != 0)\n\t{\n\t\tif (TabBarProcessReorder(tab_bar))\n\t\t\tif (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId)\n\t\t\t\tscroll_to_tab_id = tab_bar->ReorderRequestTabId;\n\t\ttab_bar->ReorderRequestTabId = 0;\n\t}\n\n\t// Tab List Popup (will alter tab_bar->BarRect and therefore the available width!)\n\tconst bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0;\n\tif (tab_list_popup_button)\n\t\tif (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x!\n\t\t\tscroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;\n\n\t// Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central\n\t// (whereas our tabs are stored as: leading, central, trailing)\n\tint shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount };\n\tg.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);\n\n\t// Compute ideal tabs widths + store them into shrink buffer\n\tImGuiTabItem* most_recently_selected_tab = NULL;\n\tint curr_section_n = -1;\n\tbool found_selected_tab_id = false;\n\tfor (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)\n\t{\n\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_n];\n\t\tIM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible);\n\n\t\tif ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button))\n\t\t\tmost_recently_selected_tab = tab;\n\t\tif (tab->ID == tab_bar->SelectedTabId)\n\t\t\tfound_selected_tab_id = true;\n\t\tif (scroll_to_tab_id == 0 && g.NavJustMovedToId == tab->ID)\n\t\t\tscroll_to_tab_id = tab->ID;\n\n\t\t// Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar.\n\t\t// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,\n\t\t// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.\n\t\tconst char* tab_name = TabBarGetTabName(tab_bar, tab);\n\t\tconst bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);\n\t\ttab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;\n\n\t\tint section_n = TabItemGetSectionIdx(tab);\n\t\tImGuiTabBarSection* section = &sections[section_n];\n\t\tsection->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);\n\t\tcurr_section_n = section_n;\n\n\t\t// Store data so we can build an array sorted by width if we need to shrink tabs down\n\t\tIM_MSVC_WARNING_SUPPRESS(6385);\n\t\tImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++];\n\t\tshrink_width_item->Index = tab_n;\n\t\tshrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth;\n\t\ttab->Width = ImMax(tab->ContentWidth, 1.0f);\n\t}\n\n\t// Compute total ideal width (used for e.g. auto-resizing a window)\n\ttab_bar->WidthAllTabsIdeal = 0.0f;\n\tfor (int section_n = 0; section_n < 3; section_n++)\n\t\ttab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing;\n\n\t// Horizontal scrolling buttons\n\t// (note that TabBarScrollButtons() will alter BarRect.Max.x)\n\tif ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll))\n\t\tif (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar))\n\t\t{\n\t\t\tscroll_to_tab_id = scroll_and_select_tab->ID;\n\t\t\tif ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0)\n\t\t\t\ttab_bar->SelectedTabId = scroll_to_tab_id;\n\t\t}\n\n\t// Shrink widths if full tabs don't fit in their allocated space\n\tfloat section_0_w = sections[0].Width + sections[0].Spacing;\n\tfloat section_1_w = sections[1].Width + sections[1].Spacing;\n\tfloat section_2_w = sections[2].Width + sections[2].Spacing;\n\tbool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth();\n\tfloat width_excess;\n\tif (central_section_is_visible)\n\t\twidth_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section\n\telse\n\t\twidth_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section\n\n\t// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore\n\tif (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))\n\t{\n\t\tint shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);\n\t\tint shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);\n\t\tShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess);\n\n\t\t// Apply shrunk values into tabs and sections\n\t\tfor (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++)\n\t\t{\n\t\t\tImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index];\n\t\t\tfloat shrinked_width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width);\n\t\t\tif (shrinked_width < 0.0f)\n\t\t\t\tcontinue;\n\n\t\t\tshrinked_width = ImMax(1.0f, shrinked_width);\n\t\t\tint section_n = TabItemGetSectionIdx(tab);\n\t\t\tsections[section_n].Width -= (tab->Width - shrinked_width);\n\t\t\ttab->Width = shrinked_width;\n\t\t}\n\t}\n\n\t// Layout all active tabs\n\tint section_tab_index = 0;\n\tfloat tab_offset = 0.0f;\n\ttab_bar->WidthAllTabs = 0.0f;\n\tfor (int section_n = 0; section_n < 3; section_n++)\n\t{\n\t\tImGuiTabBarSection* section = &sections[section_n];\n\t\tif (section_n == 2)\n\t\t\ttab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset);\n\n\t\tfor (int tab_n = 0; tab_n < section->TabCount; tab_n++)\n\t\t{\n\t\t\tImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];\n\t\t\ttab->Offset = tab_offset;\n\t\t\ttab->NameOffset = -1;\n\t\t\ttab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f);\n\t\t}\n\t\ttab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f);\n\t\ttab_offset += section->Spacing;\n\t\tsection_tab_index += section->TabCount;\n\t}\n\n\t// Clear name buffers\n\ttab_bar->TabsNames.Buf.resize(0);\n\n\t// If we have lost the selected tab, select the next most recently active one\n\tif (found_selected_tab_id == false)\n\t\ttab_bar->SelectedTabId = 0;\n\tif (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL)\n\t\tscroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID;\n\n\t// Lock in visible tab\n\ttab_bar->VisibleTabId = tab_bar->SelectedTabId;\n\ttab_bar->VisibleTabWasSubmitted = false;\n\n\t// Apply request requests\n\tif (scroll_to_tab_id != 0)\n\t\tTabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);\n\telse if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow))\n\t{\n\t\tconst float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH;\n\t\tconst ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX;\n\t\tif (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f)\n\t\t{\n\t\t\tconst float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f;\n\t\t\ttab_bar->ScrollingTargetDistToVisibility = 0.0f;\n\t\t\ttab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step);\n\t\t}\n\t\tSetKeyOwner(wheel_key, tab_bar->ID);\n\t}\n\n\t// Update scrolling\n\ttab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);\n\ttab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);\n\tif (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)\n\t{\n\t\t// Scrolling speed adjust itself so we can always reach our target in 1/3 seconds.\n\t\t// Teleport if we are aiming far off the visible line\n\t\ttab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize);\n\t\ttab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f);\n\t\tconst bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize);\n\t\ttab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed);\n\t}\n\telse\n\t{\n\t\ttab_bar->ScrollingSpeed = 0.0f;\n\t}\n\ttab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing;\n\ttab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing;\n\n\t// Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame)\n\tImGuiWindow* window = g.CurrentWindow;\n\twindow->DC.CursorPos = tab_bar->BarRect.Min;\n\tItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y);\n\twindow->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal);\n}\n\n// Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack.\nstatic ImU32   ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window)\n{\n\tIM_ASSERT(docked_window == NULL); // master branch only\n\tIM_UNUSED(docked_window);\n\tif (tab_bar->Flags & ImGuiTabBarFlags_DockNode)\n\t{\n\t\tImGuiID id = ImHashStr(label);\n\t\tKeepAliveID(id);\n\t\treturn id;\n\t}\n\telse\n\t{\n\t\tImGuiWindow* window = GImGui->CurrentWindow;\n\t\treturn window->GetID(label);\n\t}\n}\n\nstatic float ImGui::TabBarCalcMaxTabWidth()\n{\n\tImGuiContext& g = *GImGui;\n\treturn g.FontSize * 20.0f;\n}\n\nImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)\n{\n\tif (tab_id != 0)\n\t\tfor (int n = 0; n < tab_bar->Tabs.Size; n++)\n\t\t\tif (tab_bar->Tabs[n].ID == tab_id)\n\t\t\t\treturn &tab_bar->Tabs[n];\n\treturn NULL;\n}\n\n// Order = visible order, not submission order! (which is tab->BeginOrder)\nImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order)\n{\n\tif (order < 0 || order >= tab_bar->Tabs.Size)\n\t\treturn NULL;\n\treturn &tab_bar->Tabs[order];\n}\n\nImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)\n{\n\tif (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)\n\t\treturn NULL;\n\treturn &tab_bar->Tabs[tab_bar->LastTabItemIdx];\n}\n\nconst char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)\n{\n\tif (tab->NameOffset == -1)\n\t\treturn \"N/A\";\n\tIM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);\n\treturn tab_bar->TabsNames.Buf.Data + tab->NameOffset;\n}\n\n// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.\nvoid ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)\n{\n\tif (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))\n\t\ttab_bar->Tabs.erase(tab);\n\tif (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; }\n\tif (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; }\n\tif (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; }\n}\n\n// Called on manual closure attempt\nvoid ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)\n{\n\tif (tab->Flags & ImGuiTabItemFlags_Button)\n\t\treturn; // A button appended with TabItemButton().\n\n\tif (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument))\n\t{\n\t\t// This will remove a frame of lag for selecting another tab on closure.\n\t\t// However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure\n\t\ttab->WantClose = true;\n\t\tif (tab_bar->VisibleTabId == tab->ID)\n\t\t{\n\t\t\ttab->LastFrameVisible = -1;\n\t\t\ttab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup)\n\t\tif (tab_bar->VisibleTabId != tab->ID)\n\t\t\tTabBarQueueFocus(tab_bar, tab);\n\t}\n}\n\nstatic float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling)\n{\n\tscrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth());\n\treturn ImMax(scrolling, 0.0f);\n}\n\n// Note: we may scroll to tab that are not selected! e.g. using keyboard arrow keys\nstatic void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections)\n{\n\tImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id);\n\tif (tab == NULL)\n\t\treturn;\n\tif (tab->Flags & ImGuiTabItemFlags_SectionMask_)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\tfloat margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)\n\tint order = TabBarGetTabOrder(tab_bar, tab);\n\n\t// Scrolling happens only in the central section (leading/trailing sections are not scrolling)\n\tfloat scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections);\n\n\t// We make all tabs positions all relative Sections[0].Width to make code simpler\n\tfloat tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f);\n\tfloat tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f);\n\ttab_bar->ScrollingTargetDistToVisibility = 0.0f;\n\tif (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width))\n\t{\n\t\t// Scroll to the left\n\t\ttab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f);\n\t\ttab_bar->ScrollingTarget = tab_x1;\n\t}\n\telse if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width)\n\t{\n\t\t// Scroll to the right\n\t\ttab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f);\n\t\ttab_bar->ScrollingTarget = tab_x2 - scrollable_width;\n\t}\n}\n\nvoid ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)\n{\n\ttab_bar->NextSelectedTabId = tab->ID;\n}\n\nvoid ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset)\n{\n\tIM_ASSERT(offset != 0);\n\tIM_ASSERT(tab_bar->ReorderRequestTabId == 0);\n\ttab_bar->ReorderRequestTabId = tab->ID;\n\ttab_bar->ReorderRequestOffset = (ImS16)offset;\n}\n\nvoid ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos)\n{\n\tImGuiContext& g = *GImGui;\n\tIM_ASSERT(tab_bar->ReorderRequestTabId == 0);\n\tif ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0)\n\t\treturn;\n\n\tconst bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;\n\tconst float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0);\n\n\t// Count number of contiguous tabs we are crossing over\n\tconst int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1;\n\tconst int src_idx = tab_bar->Tabs.index_from_ptr(src_tab);\n\tint dst_idx = src_idx;\n\tfor (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir)\n\t{\n\t\t// Reordered tabs must share the same section\n\t\tconst ImGuiTabItem* dst_tab = &tab_bar->Tabs[i];\n\t\tif (dst_tab->Flags & ImGuiTabItemFlags_NoReorder)\n\t\t\tbreak;\n\t\tif ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_))\n\t\t\tbreak;\n\t\tdst_idx = i;\n\n\t\t// Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered.\n\t\tconst float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x;\n\t\tconst float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x;\n\t\t//GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255));\n\t\tif ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2))\n\t\t\tbreak;\n\t}\n\n\tif (dst_idx != src_idx)\n\t\tTabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx);\n}\n\nbool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)\n{\n\tImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId);\n\tif (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder))\n\t\treturn false;\n\n\t//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools\n\tint tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset;\n\tif (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)\n\t\treturn false;\n\n\t// Reordered tabs must share the same section\n\t// (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too)\n\tImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];\n\tif (tab2->Flags & ImGuiTabItemFlags_NoReorder)\n\t\treturn false;\n\tif ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_))\n\t\treturn false;\n\n\tImGuiTabItem item_tmp = *tab1;\n\tImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2;\n\tImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1;\n\tconst int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset;\n\tmemmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem));\n\t*tab2 = item_tmp;\n\n\tif (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)\n\t\tMarkIniSettingsDirty();\n\treturn true;\n}\n\nstatic ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\tconst ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f);\n\tconst float scrolling_buttons_width = arrow_button_size.x * 2.0f;\n\n\tconst ImVec2 backup_cursor_pos = window->DC.CursorPos;\n\t//window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255));\n\n\tint select_dir = 0;\n\tImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];\n\tarrow_col.w *= 0.5f;\n\n\tPushStyleColor(ImGuiCol_Text, arrow_col);\n\tPushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));\n\tconst float backup_repeat_delay = g.IO.KeyRepeatDelay;\n\tconst float backup_repeat_rate = g.IO.KeyRepeatRate;\n\tg.IO.KeyRepeatDelay = 0.250f;\n\tg.IO.KeyRepeatRate = 0.200f;\n\tfloat x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width);\n\twindow->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y);\n\tif (ArrowButtonEx(\"##<\", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))\n\t\tselect_dir = -1;\n\twindow->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y);\n\tif (ArrowButtonEx(\"##>\", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))\n\t\tselect_dir = +1;\n\tPopStyleColor(2);\n\tg.IO.KeyRepeatRate = backup_repeat_rate;\n\tg.IO.KeyRepeatDelay = backup_repeat_delay;\n\n\tImGuiTabItem* tab_to_scroll_to = NULL;\n\tif (select_dir != 0)\n\t\tif (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))\n\t\t{\n\t\t\tint selected_order = TabBarGetTabOrder(tab_bar, tab_item);\n\t\t\tint target_order = selected_order + select_dir;\n\n\t\t\t// Skip tab item buttons until another tab item is found or end is reached\n\t\t\twhile (tab_to_scroll_to == NULL)\n\t\t\t{\n\t\t\t\t// If we are at the end of the list, still scroll to make our tab visible\n\t\t\t\ttab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order];\n\n\t\t\t\t// Cross through buttons\n\t\t\t\t// (even if first/last item is a button, return it so we can update the scroll)\n\t\t\t\tif (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button)\n\t\t\t\t{\n\t\t\t\t\ttarget_order += select_dir;\n\t\t\t\t\tselected_order += select_dir;\n\t\t\t\t\ttab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\twindow->DC.CursorPos = backup_cursor_pos;\n\ttab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f;\n\n\treturn tab_to_scroll_to;\n}\n\nstatic ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\n\t// We use g.Style.FramePadding.y to match the square ArrowButton size\n\tconst float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y;\n\tconst ImVec2 backup_cursor_pos = window->DC.CursorPos;\n\twindow->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y);\n\ttab_bar->BarRect.Min.x += tab_list_popup_button_width;\n\n\tImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];\n\tarrow_col.w *= 0.5f;\n\tPushStyleColor(ImGuiCol_Text, arrow_col);\n\tPushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));\n\tbool open = BeginCombo(\"##v\", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest);\n\tPopStyleColor(2);\n\n\tImGuiTabItem* tab_to_select = NULL;\n\tif (open)\n\t{\n\t\tfor (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)\n\t\t{\n\t\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_n];\n\t\t\tif (tab->Flags & ImGuiTabItemFlags_Button)\n\t\t\t\tcontinue;\n\n\t\t\tconst char* tab_name = TabBarGetTabName(tab_bar, tab);\n\t\t\tif (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))\n\t\t\t\ttab_to_select = tab;\n\t\t}\n\t\tEndCombo();\n\t}\n\n\twindow->DC.CursorPos = backup_cursor_pos;\n\treturn tab_to_select;\n}\n\n//-------------------------------------------------------------------------\n// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.\n//-------------------------------------------------------------------------\n// - BeginTabItem()\n// - EndTabItem()\n// - TabItemButton()\n// - TabItemEx() [Internal]\n// - SetTabItemClosed()\n// - TabItemCalcSize() [Internal]\n// - TabItemBackground() [Internal]\n// - TabItemLabelAndCloseButton() [Internal]\n//-------------------------------------------------------------------------\n\nbool    ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiTabBar* tab_bar = g.CurrentTabBar;\n\tif (tab_bar == NULL)\n\t{\n\t\tIM_ASSERT_USER_ERROR(tab_bar, \"Needs to be called between BeginTabBar() and EndTabBar()!\");\n\t\treturn false;\n\t}\n\tIM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead!\n\n\tbool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);\n\tif (ret && !(flags & ImGuiTabItemFlags_NoPushId))\n\t{\n\t\tImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];\n\t\tPushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label)\n\t}\n\treturn ret;\n}\n\nvoid    ImGui::EndTabItem()\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiTabBar* tab_bar = g.CurrentTabBar;\n\tif (tab_bar == NULL)\n\t{\n\t\tIM_ASSERT_USER_ERROR(tab_bar != NULL, \"Needs to be called between BeginTabBar() and EndTabBar()!\");\n\t\treturn;\n\t}\n\tIM_ASSERT(tab_bar->LastTabItemIdx >= 0);\n\tImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];\n\tif (!(tab->Flags & ImGuiTabItemFlags_NoPushId))\n\t\tPopID();\n}\n\nbool    ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags)\n{\n\tImGuiContext& g = *GImGui;\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiTabBar* tab_bar = g.CurrentTabBar;\n\tif (tab_bar == NULL)\n\t{\n\t\tIM_ASSERT_USER_ERROR(tab_bar != NULL, \"Needs to be called between BeginTabBar() and EndTabBar()!\");\n\t\treturn false;\n\t}\n\treturn TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL);\n}\n\nbool    ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)\n{\n\t// Layout whole tab bar if not already done\n\tImGuiContext& g = *GImGui;\n\tif (tab_bar->WantLayout)\n\t{\n\t\tImGuiNextItemData backup_next_item_data = g.NextItemData;\n\t\tTabBarLayout(tab_bar);\n\t\tg.NextItemData = backup_next_item_data;\n\t}\n\tImGuiWindow* window = g.CurrentWindow;\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tconst ImGuiStyle& style = g.Style;\n\tconst ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window);\n\n\t// If the user called us with *p_open == false, we early out and don't render.\n\t// We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.\n\tIMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);\n\tif (p_open && !*p_open)\n\t{\n\t\tItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav);\n\t\treturn false;\n\t}\n\n\tIM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button));\n\tIM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing\n\n\t// Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented)\n\tif (flags & ImGuiTabItemFlags_NoCloseButton)\n\t\tp_open = NULL;\n\telse if (p_open == NULL)\n\t\tflags |= ImGuiTabItemFlags_NoCloseButton;\n\n\t// Acquire tab data\n\tImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id);\n\tbool tab_is_new = false;\n\tif (tab == NULL)\n\t{\n\t\ttab_bar->Tabs.push_back(ImGuiTabItem());\n\t\ttab = &tab_bar->Tabs.back();\n\t\ttab->ID = id;\n\t\ttab_bar->TabsAddedNew = tab_is_new = true;\n\t}\n\ttab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab);\n\n\t// Calculate tab contents size\n\tImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument));\n\ttab->RequestedWidth = -1.0f;\n\tif (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)\n\t\tsize.x = tab->RequestedWidth = g.NextItemData.Width;\n\tif (tab_is_new)\n\t\ttab->Width = ImMax(1.0f, size.x);\n\ttab->ContentWidth = size.x;\n\ttab->BeginOrder = tab_bar->TabsActiveCount++;\n\n\tconst bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);\n\tconst bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;\n\tconst bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);\n\tconst bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument);\n\tconst bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;\n\ttab->LastFrameVisible = g.FrameCount;\n\ttab->Flags = flags;\n\n\t// Append name _WITH_ the zero-terminator\n\tif (docked_window != NULL)\n\t{\n\t\tIM_ASSERT(docked_window == NULL); // master branch only\n\t}\n\telse\n\t{\n\t\ttab->NameOffset = (ImS32)tab_bar->TabsNames.size();\n\t\ttab_bar->TabsNames.append(label, label + strlen(label) + 1);\n\t}\n\n\t// Update selected tab\n\tif (!is_tab_button)\n\t{\n\t\tif (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)\n\t\t\tif (!tab_bar_appearing || tab_bar->SelectedTabId == 0)\n\t\t\t\tTabBarQueueFocus(tab_bar, tab); // New tabs gets activated\n\t\tif ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar\n\t\t\tTabBarQueueFocus(tab_bar, tab);\n\t}\n\n\t// Lock visibility\n\t// (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!)\n\tbool tab_contents_visible = (tab_bar->VisibleTabId == id);\n\tif (tab_contents_visible)\n\t\ttab_bar->VisibleTabWasSubmitted = true;\n\n\t// On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches\n\tif (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing)\n\t\tif (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs))\n\t\t\ttab_contents_visible = true;\n\n\t// Note that tab_is_new is not necessarily the same as tab_appearing! When a tab bar stops being submitted\n\t// and then gets submitted again, the tabs will have 'tab_appearing=true' but 'tab_is_new=false'.\n\tif (tab_appearing && (!tab_bar_appearing || tab_is_new))\n\t{\n\t\tItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav);\n\t\tif (is_tab_button)\n\t\t\treturn false;\n\t\treturn tab_contents_visible;\n\t}\n\n\tif (tab_bar->SelectedTabId == id)\n\t\ttab->LastFrameSelected = g.FrameCount;\n\n\t// Backup current layout position\n\tconst ImVec2 backup_main_cursor_pos = window->DC.CursorPos;\n\n\t// Layout\n\tconst bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;\n\tsize.x = tab->Width;\n\tif (is_central_section)\n\t\twindow->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f);\n\telse\n\t\twindow->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);\n\tImVec2 pos = window->DC.CursorPos;\n\tImRect bb(pos, pos + size);\n\n\t// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)\n\tconst bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX);\n\tif (want_clip_rect)\n\t\tPushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true);\n\n\tImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;\n\tItemSize(bb.GetSize(), style.FramePadding.y);\n\twindow->DC.CursorMaxPos = backup_cursor_max_pos;\n\n\tif (!ItemAdd(bb, id))\n\t{\n\t\tif (want_clip_rect)\n\t\t\tPopClipRect();\n\t\twindow->DC.CursorPos = backup_main_cursor_pos;\n\t\treturn tab_contents_visible;\n\t}\n\n\t// Click to Select a tab\n\t// Allow the close button to overlap\n\tImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);\n\tif (g.DragDropActive)\n\t\tbutton_flags |= ImGuiButtonFlags_PressedOnDragDropHold;\n\tbool hovered, held;\n\tbool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);\n\tif (pressed && !is_tab_button)\n\t\tTabBarQueueFocus(tab_bar, tab);\n\n\t// Drag and drop: re-order tabs\n\tif (held && !tab_appearing && IsMouseDragging(0))\n\t{\n\t\tif (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable))\n\t\t{\n\t\t\t// While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x\n\t\t\tif (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)\n\t\t\t{\n\t\t\t\tTabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);\n\t\t\t}\n\t\t\telse if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)\n\t\t\t{\n\t\t\t\tTabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);\n\t\t\t}\n\t\t}\n\t}\n\n#if 0\n\tif (hovered && g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth)\n\t{\n\t\t// Enlarge tab display when hovering\n\t\tbb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)));\n\t\tdisplay_draw_list = GetForegroundDrawList(window);\n\t\tTabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive));\n\t}\n#endif\n\n\t// Render tab shape\n\tImDrawList* display_draw_list = window->DrawList;\n\tconst ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused));\n\tTabItemBackground(display_draw_list, bb, flags, tab_col);\n\tRenderNavHighlight(bb, id);\n\n\t// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.\n\tconst bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);\n\tif (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)\n\t\tTabBarQueueFocus(tab_bar, tab);\n\n\tif (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)\n\t\tflags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;\n\n\t// Render tab label, process close button\n\tconst ImGuiID close_button_id = p_open ? GetIDWithSeed(\"#CLOSE\", NULL, id) : 0;\n\tbool just_closed;\n\tbool text_clipped;\n\tTabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);\n\tif (just_closed && p_open != NULL)\n\t{\n\t\t*p_open = false;\n\t\tTabBarCloseTab(tab_bar, tab);\n\t}\n\n\t// Restore main window position so user can draw there\n\tif (want_clip_rect)\n\t\tPopClipRect();\n\twindow->DC.CursorPos = backup_main_cursor_pos;\n\n\t// Tooltip\n\t// (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok)\n\t// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)\n\t// FIXME: This is a mess.\n\t// FIXME: We may want disabled tab to still display the tooltip?\n\tif (text_clipped && g.HoveredId == id && !held)\n\t\tif (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))\n\t\t\tSetItemTooltip(\"%.*s\", (int)(FindRenderedTextEnd(label) - label), label);\n\n\tIM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected\n\tif (is_tab_button)\n\t\treturn pressed;\n\treturn tab_contents_visible;\n}\n\n// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed.\n// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar().\n// Tabs closed by the close button will automatically be flagged to avoid this issue.\nvoid    ImGui::SetTabItemClosed(const char* label)\n{\n\tImGuiContext& g = *GImGui;\n\tbool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode);\n\tif (is_within_manual_tab_bar)\n\t{\n\t\tImGuiTabBar* tab_bar = g.CurrentTabBar;\n\t\tImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL);\n\t\tif (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))\n\t\t\ttab->WantClose = true; // Will be processed by next call to TabBarLayout()\n\t}\n}\n\nImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker)\n{\n\tImGuiContext& g = *GImGui;\n\tImVec2 label_size = CalcTextSize(label, NULL, true);\n\tImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f);\n\tif (has_close_button_or_unsaved_marker)\n\t\tsize.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle.\n\telse\n\t\tsize.x += g.Style.FramePadding.x + 1.0f;\n\treturn ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y);\n}\n\nImVec2 ImGui::TabItemCalcSize(ImGuiWindow*)\n{\n\tIM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch.\n\treturn ImVec2(0.0f, 0.0f);\n}\n\nvoid ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)\n{\n\t// While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking \"detached\" from it.\n\tImGuiContext& g = *GImGui;\n\tconst float width = bb.GetWidth();\n\tIM_UNUSED(flags);\n\tIM_ASSERT(width > 0.0f);\n\tconst float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f));\n\tconst float y1 = bb.Min.y + 1.0f;\n\tconst float y2 = bb.Max.y - 1.0f;\n\tdraw_list->PathLineTo(ImVec2(bb.Min.x, y2));\n\tdraw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9);\n\tdraw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);\n\tdraw_list->PathLineTo(ImVec2(bb.Max.x, y2));\n\tdraw_list->PathFillConvex(col);\n\tif (g.Style.TabBorderSize > 0.0f)\n\t{\n\t\tdraw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2));\n\t\tdraw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9);\n\t\tdraw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12);\n\t\tdraw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2));\n\t\tdraw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize);\n\t}\n}\n\n// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic\n// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter.\nvoid ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped)\n{\n\tImGuiContext& g = *GImGui;\n\tImVec2 label_size = CalcTextSize(label, NULL, true);\n\n\tif (out_just_closed)\n\t\t*out_just_closed = false;\n\tif (out_text_clipped)\n\t\t*out_text_clipped = false;\n\n\tif (bb.GetWidth() <= 1.0f)\n\t\treturn;\n\n\t// In Style V2 we'll have full override of all colors per state (e.g. focused, selected)\n\t// But right now if you want to alter text color of tabs this is what you need to do.\n#if 0\n\tconst float backup_alpha = g.Style.Alpha;\n\tif (!is_contents_visible)\n\t\tg.Style.Alpha *= 0.7f;\n#endif\n\n\t// Render text label (with clipping + alpha gradient) + unsaved marker\n\tImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y);\n\tImRect text_ellipsis_clip_bb = text_pixel_clip_bb;\n\n\t// Return clipped state ignoring the close button\n\tif (out_text_clipped)\n\t{\n\t\t*out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x;\n\t\t//draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255));\n\t}\n\n\tconst float button_sz = g.FontSize;\n\tconst ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y);\n\n\t// Close Button & Unsaved Marker\n\t// We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap()\n\t//  'hovered' will be true when hovering the Tab but NOT when hovering the close button\n\t//  'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button\n\t//  'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false\n\tbool close_button_pressed = false;\n\tbool close_button_visible = false;\n\tif (close_button_id != 0)\n\t\tif (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton))\n\t\t\tif (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id)\n\t\t\t\tclose_button_visible = true;\n\tbool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x);\n\n\tif (close_button_visible)\n\t{\n\t\tImGuiLastItemData last_item_backup = g.LastItemData;\n\t\tif (CloseButton(close_button_id, button_pos))\n\t\t\tclose_button_pressed = true;\n\t\tg.LastItemData = last_item_backup;\n\n\t\t// Close with middle mouse button\n\t\tif (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))\n\t\t\tclose_button_pressed = true;\n\t}\n\telse if (unsaved_marker_visible)\n\t{\n\t\tconst ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f);\n\t\tRenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));\n\t}\n\n\t// This is all rather complicated\n\t// (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position)\n\t// FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist..\n\tfloat ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f;\n\tif (close_button_visible || unsaved_marker_visible)\n\t{\n\t\ttext_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f);\n\t\ttext_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f;\n\t\tellipsis_max_x = text_pixel_clip_bb.Max.x;\n\t}\n\tRenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size);\n\n#if 0\n\tif (!is_contents_visible)\n\t\tg.Style.Alpha = backup_alpha;\n#endif\n\n\tif (out_just_closed)\n\t\t*out_just_closed = close_button_pressed;\n}\n\n#endif // #ifndef IMGUI_DISABLE"
  },
  {
    "path": "KBotExt/imgui/imstb_rectpack.h",
    "content": "// [DEAR IMGUI]\n// This is a slightly modified version of stb_rect_pack.h 1.01.\n// Grep for [DEAR IMGUI] to find the changes.\n//\n// stb_rect_pack.h - v1.01 - public domain - rectangle packing\n// Sean Barrett 2014\n//\n// Useful for e.g. packing rectangular textures into an atlas.\n// Does not do rotation.\n//\n// Before #including,\n//\n//    #define STB_RECT_PACK_IMPLEMENTATION\n//\n// in the file that you want to have the implementation.\n//\n// Not necessarily the awesomest packing method, but better than\n// the totally naive one in stb_truetype (which is primarily what\n// this is meant to replace).\n//\n// Has only had a few tests run, may have issues.\n//\n// More docs to come.\n//\n// No memory allocations; uses qsort() and assert() from stdlib.\n// Can override those by defining STBRP_SORT and STBRP_ASSERT.\n//\n// This library currently uses the Skyline Bottom-Left algorithm.\n//\n// Please note: better rectangle packers are welcome! Please\n// implement them to the same API, but with a different init\n// function.\n//\n// Credits\n//\n//  Library\n//    Sean Barrett\n//  Minor features\n//    Martins Mozeiko\n//    github:IntellectualKitty\n//\n//  Bugfixes / warning fixes\n//    Jeremy Jaussaud\n//    Fabian Giesen\n//\n// Version history:\n//\n//     1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section\n//     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles\n//     0.99  (2019-02-07)  warning fixes\n//     0.11  (2017-03-03)  return packing success/fail result\n//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings\n//     0.09  (2016-08-27)  fix compiler warnings\n//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)\n//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)\n//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort\n//     0.05:  added STBRP_ASSERT to allow replacing assert\n//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support\n//     0.01:  initial release\n//\n// LICENSE\n//\n//   See end of file for license information.\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//       INCLUDE SECTION\n//\n\n#ifndef STB_INCLUDE_STB_RECT_PACK_H\n#define STB_INCLUDE_STB_RECT_PACK_H\n\n#define STB_RECT_PACK_VERSION  1\n\n#ifdef STBRP_STATIC\n#define STBRP_DEF static\n#else\n#define STBRP_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\ttypedef struct stbrp_context stbrp_context;\n\ttypedef struct stbrp_node    stbrp_node;\n\ttypedef struct stbrp_rect    stbrp_rect;\n\n\ttypedef int            stbrp_coord;\n\n#define STBRP__MAXVAL  0x7fffffff\n\t// Mostly for internal use, but this is the maximum supported coordinate value.\n\n\tSTBRP_DEF int stbrp_pack_rects(stbrp_context* context, stbrp_rect* rects, int num_rects);\n\t// Assign packed locations to rectangles. The rectangles are of type\n\t// 'stbrp_rect' defined below, stored in the array 'rects', and there\n\t// are 'num_rects' many of them.\n\t//\n\t// Rectangles which are successfully packed have the 'was_packed' flag\n\t// set to a non-zero value and 'x' and 'y' store the minimum location\n\t// on each axis (i.e. bottom-left in cartesian coordinates, top-left\n\t// if you imagine y increasing downwards). Rectangles which do not fit\n\t// have the 'was_packed' flag set to 0.\n\t//\n\t// You should not try to access the 'rects' array from another thread\n\t// while this function is running, as the function temporarily reorders\n\t// the array while it executes.\n\t//\n\t// To pack into another rectangle, you need to call stbrp_init_target\n\t// again. To continue packing into the same rectangle, you can call\n\t// this function again. Calling this multiple times with multiple rect\n\t// arrays will probably produce worse packing results than calling it\n\t// a single time with the full rectangle array, but the option is\n\t// available.\n\t//\n\t// The function returns 1 if all of the rectangles were successfully\n\t// packed and 0 otherwise.\n\n\tstruct stbrp_rect\n\t{\n\t\t// reserved for your use:\n\t\tint            id;\n\n\t\t// input:\n\t\tstbrp_coord    w, h;\n\n\t\t// output:\n\t\tstbrp_coord    x, y;\n\t\tint            was_packed;  // non-zero if valid packing\n\t}; // 16 bytes, nominally\n\n\tSTBRP_DEF void stbrp_init_target(stbrp_context* context, int width, int height, stbrp_node* nodes, int num_nodes);\n\t// Initialize a rectangle packer to:\n\t//    pack a rectangle that is 'width' by 'height' in dimensions\n\t//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long\n\t//\n\t// You must call this function every time you start packing into a new target.\n\t//\n\t// There is no \"shutdown\" function. The 'nodes' memory must stay valid for\n\t// the following stbrp_pack_rects() call (or calls), but can be freed after\n\t// the call (or calls) finish.\n\t//\n\t// Note: to guarantee best results, either:\n\t//       1. make sure 'num_nodes' >= 'width'\n\t//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'\n\t//\n\t// If you don't do either of the above things, widths will be quantized to multiples\n\t// of small integers to guarantee the algorithm doesn't run out of temporary storage.\n\t//\n\t// If you do #2, then the non-quantized algorithm will be used, but the algorithm\n\t// may run out of temporary storage and be unable to pack some rectangles.\n\n\tSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context* context, int allow_out_of_mem);\n\t// Optionally call this function after init but before doing any packing to\n\t// change the handling of the out-of-temp-memory scenario, described above.\n\t// If you call init again, this will be reset to the default (false).\n\n\tSTBRP_DEF void stbrp_setup_heuristic(stbrp_context* context, int heuristic);\n\t// Optionally select which packing heuristic the library should use. Different\n\t// heuristics will produce better/worse results for different data sets.\n\t// If you call init again, this will be reset to the default.\n\n\tenum\n\t{\n\t\tSTBRP_HEURISTIC_Skyline_default = 0,\n\t\tSTBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,\n\t\tSTBRP_HEURISTIC_Skyline_BF_sortHeight\n\t};\n\n\t//////////////////////////////////////////////////////////////////////////////\n\t//\n\t// the details of the following structures don't matter to you, but they must\n\t// be visible so you can handle the memory allocations for them\n\n\tstruct stbrp_node\n\t{\n\t\tstbrp_coord  x, y;\n\t\tstbrp_node* next;\n\t};\n\n\tstruct stbrp_context\n\t{\n\t\tint width;\n\t\tint height;\n\t\tint align;\n\t\tint init_mode;\n\t\tint heuristic;\n\t\tint num_nodes;\n\t\tstbrp_node* active_head;\n\t\tstbrp_node* free_head;\n\t\tstbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'\n\t};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//     IMPLEMENTATION SECTION\n//\n\n#ifdef STB_RECT_PACK_IMPLEMENTATION\n#ifndef STBRP_SORT\n#include <stdlib.h>\n#define STBRP_SORT qsort\n#endif\n\n#ifndef STBRP_ASSERT\n#include <assert.h>\n#define STBRP_ASSERT assert\n#endif\n\n#ifdef _MSC_VER\n#define STBRP__NOTUSED(v)  (void)(v)\n#define STBRP__CDECL       __cdecl\n#else\n#define STBRP__NOTUSED(v)  (void)sizeof(v)\n#define STBRP__CDECL\n#endif\n\nenum\n{\n\tSTBRP__INIT_skyline = 1\n};\n\nSTBRP_DEF void stbrp_setup_heuristic(stbrp_context* context, int heuristic)\n{\n\tswitch (context->init_mode) {\n\tcase STBRP__INIT_skyline:\n\t\tSTBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);\n\t\tcontext->heuristic = heuristic;\n\t\tbreak;\n\tdefault:\n\t\tSTBRP_ASSERT(0);\n\t}\n}\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context* context, int allow_out_of_mem)\n{\n\tif (allow_out_of_mem)\n\t\t// if it's ok to run out of memory, then don't bother aligning them;\n\t\t// this gives better packing, but may fail due to OOM (even though\n\t\t// the rectangles easily fit). @TODO a smarter approach would be to only\n\t\t// quantize once we've hit OOM, then we could get rid of this parameter.\n\t\tcontext->align = 1;\n\telse {\n\t\t// if it's not ok to run out of memory, then quantize the widths\n\t\t// so that num_nodes is always enough nodes.\n\t\t//\n\t\t// I.e. num_nodes * align >= width\n\t\t//                  align >= width / num_nodes\n\t\t//                  align = ceil(width/num_nodes)\n\n\t\tcontext->align = (context->width + context->num_nodes - 1) / context->num_nodes;\n\t}\n}\n\nSTBRP_DEF void stbrp_init_target(stbrp_context* context, int width, int height, stbrp_node* nodes, int num_nodes)\n{\n\tint i;\n\n\tfor (i = 0; i < num_nodes - 1; ++i)\n\t\tnodes[i].next = &nodes[i + 1];\n\tnodes[i].next = NULL;\n\tcontext->init_mode = STBRP__INIT_skyline;\n\tcontext->heuristic = STBRP_HEURISTIC_Skyline_default;\n\tcontext->free_head = &nodes[0];\n\tcontext->active_head = &context->extra[0];\n\tcontext->width = width;\n\tcontext->height = height;\n\tcontext->num_nodes = num_nodes;\n\tstbrp_setup_allow_out_of_mem(context, 0);\n\n\t// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)\n\tcontext->extra[0].x = 0;\n\tcontext->extra[0].y = 0;\n\tcontext->extra[0].next = &context->extra[1];\n\tcontext->extra[1].x = (stbrp_coord)width;\n\tcontext->extra[1].y = (1 << 30);\n\tcontext->extra[1].next = NULL;\n}\n\n// find minimum y position if it starts at x1\nstatic int stbrp__skyline_find_min_y(stbrp_context* c, stbrp_node* first, int x0, int width, int* pwaste)\n{\n\tstbrp_node* node = first;\n\tint x1 = x0 + width;\n\tint min_y, visited_width, waste_area;\n\n\tSTBRP__NOTUSED(c);\n\n\tSTBRP_ASSERT(first->x <= x0);\n\n#if 0\n\t// skip in case we're past the node\n\twhile (node->next->x <= x0)\n\t\t++node;\n#else\n\tSTBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency\n#endif\n\n\tSTBRP_ASSERT(node->x <= x0);\n\n\tmin_y = 0;\n\twaste_area = 0;\n\tvisited_width = 0;\n\twhile (node->x < x1) {\n\t\tif (node->y > min_y) {\n\t\t\t// raise min_y higher.\n\t\t\t// we've accounted for all waste up to min_y,\n\t\t\t// but we'll now add more waste for everything we've visted\n\t\t\twaste_area += visited_width * (node->y - min_y);\n\t\t\tmin_y = node->y;\n\t\t\t// the first time through, visited_width might be reduced\n\t\t\tif (node->x < x0)\n\t\t\t\tvisited_width += node->next->x - x0;\n\t\t\telse\n\t\t\t\tvisited_width += node->next->x - node->x;\n\t\t}\n\t\telse {\n\t\t\t// add waste area\n\t\t\tint under_width = node->next->x - node->x;\n\t\t\tif (under_width + visited_width > width)\n\t\t\t\tunder_width = width - visited_width;\n\t\t\twaste_area += under_width * (min_y - node->y);\n\t\t\tvisited_width += under_width;\n\t\t}\n\t\tnode = node->next;\n\t}\n\n\t*pwaste = waste_area;\n\treturn min_y;\n}\n\ntypedef struct\n{\n\tint x, y;\n\tstbrp_node** prev_link;\n} stbrp__findresult;\n\nstatic stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context* c, int width, int height)\n{\n\tint best_waste = (1 << 30), best_x, best_y = (1 << 30);\n\tstbrp__findresult fr;\n\tstbrp_node** prev, * node, * tail, ** best = NULL;\n\n\t// align to multiple of c->align\n\twidth = (width + c->align - 1);\n\twidth -= width % c->align;\n\tSTBRP_ASSERT(width % c->align == 0);\n\n\t// if it can't possibly fit, bail immediately\n\tif (width > c->width || height > c->height) {\n\t\tfr.prev_link = NULL;\n\t\tfr.x = fr.y = 0;\n\t\treturn fr;\n\t}\n\n\tnode = c->active_head;\n\tprev = &c->active_head;\n\twhile (node->x + width <= c->width) {\n\t\tint y, waste;\n\t\ty = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);\n\t\tif (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL\n\t\t\t// bottom left\n\t\t\tif (y < best_y) {\n\t\t\t\tbest_y = y;\n\t\t\t\tbest = prev;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// best-fit\n\t\t\tif (y + height <= c->height) {\n\t\t\t\t// can only use it if it first vertically\n\t\t\t\tif (y < best_y || (y == best_y && waste < best_waste)) {\n\t\t\t\t\tbest_y = y;\n\t\t\t\t\tbest_waste = waste;\n\t\t\t\t\tbest = prev;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprev = &node->next;\n\t\tnode = node->next;\n\t}\n\n\tbest_x = (best == NULL) ? 0 : (*best)->x;\n\n\t// if doing best-fit (BF), we also have to try aligning right edge to each node position\n\t//\n\t// e.g, if fitting\n\t//\n\t//     ____________________\n\t//    |____________________|\n\t//\n\t//            into\n\t//\n\t//   |                         |\n\t//   |             ____________|\n\t//   |____________|\n\t//\n\t// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned\n\t//\n\t// This makes BF take about 2x the time\n\n\tif (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {\n\t\ttail = c->active_head;\n\t\tnode = c->active_head;\n\t\tprev = &c->active_head;\n\t\t// find first node that's admissible\n\t\twhile (tail->x < width)\n\t\t\ttail = tail->next;\n\t\twhile (tail) {\n\t\t\tint xpos = tail->x - width;\n\t\t\tint y, waste;\n\t\t\tSTBRP_ASSERT(xpos >= 0);\n\t\t\t// find the left position that matches this\n\t\t\twhile (node->next->x <= xpos) {\n\t\t\t\tprev = &node->next;\n\t\t\t\tnode = node->next;\n\t\t\t}\n\t\t\tSTBRP_ASSERT(node->next->x > xpos && node->x <= xpos);\n\t\t\ty = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);\n\t\t\tif (y + height <= c->height) {\n\t\t\t\tif (y <= best_y) {\n\t\t\t\t\tif (y < best_y || waste < best_waste || (waste == best_waste && xpos < best_x)) {\n\t\t\t\t\t\tbest_x = xpos;\n\t\t\t\t\t\t//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]\n\t\t\t\t\t\tbest_y = y;\n\t\t\t\t\t\tbest_waste = waste;\n\t\t\t\t\t\tbest = prev;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttail = tail->next;\n\t\t}\n\t}\n\n\tfr.prev_link = best;\n\tfr.x = best_x;\n\tfr.y = best_y;\n\treturn fr;\n}\n\nstatic stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context* context, int width, int height)\n{\n\t// find best position according to heuristic\n\tstbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);\n\tstbrp_node* node, * cur;\n\n\t// bail if:\n\t//    1. it failed\n\t//    2. the best node doesn't fit (we don't always check this)\n\t//    3. we're out of memory\n\tif (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {\n\t\tres.prev_link = NULL;\n\t\treturn res;\n\t}\n\n\t// on success, create new node\n\tnode = context->free_head;\n\tnode->x = (stbrp_coord)res.x;\n\tnode->y = (stbrp_coord)(res.y + height);\n\n\tcontext->free_head = node->next;\n\n\t// insert the new node into the right starting point, and\n\t// let 'cur' point to the remaining nodes needing to be\n\t// stiched back in\n\n\tcur = *res.prev_link;\n\tif (cur->x < res.x) {\n\t\t// preserve the existing one, so start testing with the next one\n\t\tstbrp_node* next = cur->next;\n\t\tcur->next = node;\n\t\tcur = next;\n\t}\n\telse {\n\t\t*res.prev_link = node;\n\t}\n\n\t// from here, traverse cur and free the nodes, until we get to one\n\t// that shouldn't be freed\n\twhile (cur->next && cur->next->x <= res.x + width) {\n\t\tstbrp_node* next = cur->next;\n\t\t// move the current node to the free list\n\t\tcur->next = context->free_head;\n\t\tcontext->free_head = cur;\n\t\tcur = next;\n\t}\n\n\t// stitch the list back in\n\tnode->next = cur;\n\n\tif (cur->x < res.x + width)\n\t\tcur->x = (stbrp_coord)(res.x + width);\n\n#ifdef _DEBUG\n\tcur = context->active_head;\n\twhile (cur->x < context->width) {\n\t\tSTBRP_ASSERT(cur->x < cur->next->x);\n\t\tcur = cur->next;\n\t}\n\tSTBRP_ASSERT(cur->next == NULL);\n\n\t{\n\t\tint count = 0;\n\t\tcur = context->active_head;\n\t\twhile (cur) {\n\t\t\tcur = cur->next;\n\t\t\t++count;\n\t\t}\n\t\tcur = context->free_head;\n\t\twhile (cur) {\n\t\t\tcur = cur->next;\n\t\t\t++count;\n\t\t}\n\t\tSTBRP_ASSERT(count == context->num_nodes + 2);\n\t}\n#endif\n\n\treturn res;\n}\n\nstatic int STBRP__CDECL rect_height_compare(const void* a, const void* b)\n{\n\tconst stbrp_rect* p = (const stbrp_rect*)a;\n\tconst stbrp_rect* q = (const stbrp_rect*)b;\n\tif (p->h > q->h)\n\t\treturn -1;\n\tif (p->h < q->h)\n\t\treturn  1;\n\treturn (p->w > q->w) ? -1 : (p->w < q->w);\n}\n\nstatic int STBRP__CDECL rect_original_order(const void* a, const void* b)\n{\n\tconst stbrp_rect* p = (const stbrp_rect*)a;\n\tconst stbrp_rect* q = (const stbrp_rect*)b;\n\treturn (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);\n}\n\nSTBRP_DEF int stbrp_pack_rects(stbrp_context* context, stbrp_rect* rects, int num_rects)\n{\n\tint i, all_rects_packed = 1;\n\n\t// we use the 'was_packed' field internally to allow sorting/unsorting\n\tfor (i = 0; i < num_rects; ++i) {\n\t\trects[i].was_packed = i;\n\t}\n\n\t// sort according to heuristic\n\tSTBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);\n\n\tfor (i = 0; i < num_rects; ++i) {\n\t\tif (rects[i].w == 0 || rects[i].h == 0) {\n\t\t\trects[i].x = rects[i].y = 0;  // empty rect needs no space\n\t\t}\n\t\telse {\n\t\t\tstbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);\n\t\t\tif (fr.prev_link) {\n\t\t\t\trects[i].x = (stbrp_coord)fr.x;\n\t\t\t\trects[i].y = (stbrp_coord)fr.y;\n\t\t\t}\n\t\t\telse {\n\t\t\t\trects[i].x = rects[i].y = STBRP__MAXVAL;\n\t\t\t}\n\t\t}\n\t}\n\n\t// unsort\n\tSTBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);\n\n\t// set was_packed flags and all_rects_packed status\n\tfor (i = 0; i < num_rects; ++i) {\n\t\trects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);\n\t\tif (!rects[i].was_packed)\n\t\t\tall_rects_packed = 0;\n\t}\n\n\t// return the all_rects_packed status\n\treturn all_rects_packed;\n}\n#endif\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "KBotExt/imgui/imstb_textedit.h",
    "content": "// [DEAR IMGUI]\n// This is a slightly modified version of stb_textedit.h 1.14.\n// Those changes would need to be pushed into nothings/stb:\n// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)\n// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000)\n// Grep for [DEAR IMGUI] to find the changes.\n\n// stb_textedit.h - v1.14  - public domain - Sean Barrett\n// Development of this library was sponsored by RAD Game Tools\n//\n// This C header file implements the guts of a multi-line text-editing\n// widget; you implement display, word-wrapping, and low-level string\n// insertion/deletion, and stb_textedit will map user inputs into\n// insertions & deletions, plus updates to the cursor position,\n// selection state, and undo state.\n//\n// It is intended for use in games and other systems that need to build\n// their own custom widgets and which do not have heavy text-editing\n// requirements (this library is not recommended for use for editing large\n// texts, as its performance does not scale and it has limited undo).\n//\n// Non-trivial behaviors are modelled after Windows text controls.\n//\n//\n// LICENSE\n//\n// See end of file for license information.\n//\n//\n// DEPENDENCIES\n//\n// Uses the C runtime function 'memmove', which you can override\n// by defining STB_TEXTEDIT_memmove before the implementation.\n// Uses no other functions. Performs no runtime allocations.\n//\n//\n// VERSION HISTORY\n//\n//   1.14 (2021-07-11) page up/down, various fixes\n//   1.13 (2019-02-07) fix bug in undo size management\n//   1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash\n//   1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield\n//   1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual\n//   1.9  (2016-08-27) customizable move-by-word\n//   1.8  (2016-04-02) better keyboard handling when mouse button is down\n//   1.7  (2015-09-13) change y range handling in case baseline is non-0\n//   1.6  (2015-04-15) allow STB_TEXTEDIT_memmove\n//   1.5  (2014-09-10) add support for secondary keys for OS X\n//   1.4  (2014-08-17) fix signed/unsigned warnings\n//   1.3  (2014-06-19) fix mouse clicking to round to nearest char boundary\n//   1.2  (2014-05-27) fix some RAD types that had crept into the new code\n//   1.1  (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE )\n//   1.0  (2012-07-26) improve documentation, initial public release\n//   0.3  (2012-02-24) bugfixes, single-line mode; insert mode\n//   0.2  (2011-11-28) fixes to undo/redo\n//   0.1  (2010-07-08) initial version\n//\n// ADDITIONAL CONTRIBUTORS\n//\n//   Ulf Winklemann: move-by-word in 1.1\n//   Fabian Giesen: secondary key inputs in 1.5\n//   Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6\n//   Louis Schnellbach: page up/down in 1.14\n//\n//   Bugfixes:\n//      Scott Graham\n//      Daniel Keller\n//      Omar Cornut\n//      Dan Thompson\n//\n// USAGE\n//\n// This file behaves differently depending on what symbols you define\n// before including it.\n//\n//\n// Header-file mode:\n//\n//   If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this,\n//   it will operate in \"header file\" mode. In this mode, it declares a\n//   single public symbol, STB_TexteditState, which encapsulates the current\n//   state of a text widget (except for the string, which you will store\n//   separately).\n//\n//   To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a\n//   primitive type that defines a single character (e.g. char, wchar_t, etc).\n//\n//   To save space or increase undo-ability, you can optionally define the\n//   following things that are used by the undo system:\n//\n//      STB_TEXTEDIT_POSITIONTYPE         small int type encoding a valid cursor position\n//      STB_TEXTEDIT_UNDOSTATECOUNT       the number of undo states to allow\n//      STB_TEXTEDIT_UNDOCHARCOUNT        the number of characters to store in the undo buffer\n//\n//   If you don't define these, they are set to permissive types and\n//   moderate sizes. The undo system does no memory allocations, so\n//   it grows STB_TexteditState by the worst-case storage which is (in bytes):\n//\n//        [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATECOUNT\n//      +          sizeof(STB_TEXTEDIT_CHARTYPE)      * STB_TEXTEDIT_UNDOCHARCOUNT\n//\n//\n// Implementation mode:\n//\n//   If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it\n//   will compile the implementation of the text edit widget, depending\n//   on a large number of symbols which must be defined before the include.\n//\n//   The implementation is defined only as static functions. You will then\n//   need to provide your own APIs in the same file which will access the\n//   static functions.\n//\n//   The basic concept is that you provide a \"string\" object which\n//   behaves like an array of characters. stb_textedit uses indices to\n//   refer to positions in the string, implicitly representing positions\n//   in the displayed textedit. This is true for both plain text and\n//   rich text; even with rich text stb_truetype interacts with your\n//   code as if there was an array of all the displayed characters.\n//\n// Symbols that must be the same in header-file and implementation mode:\n//\n//     STB_TEXTEDIT_CHARTYPE             the character type\n//     STB_TEXTEDIT_POSITIONTYPE         small type that is a valid cursor position\n//     STB_TEXTEDIT_UNDOSTATECOUNT       the number of undo states to allow\n//     STB_TEXTEDIT_UNDOCHARCOUNT        the number of characters to store in the undo buffer\n//\n// Symbols you must define for implementation mode:\n//\n//    STB_TEXTEDIT_STRING               the type of object representing a string being edited,\n//                                      typically this is a wrapper object with other data you need\n//\n//    STB_TEXTEDIT_STRINGLEN(obj)       the length of the string (ideally O(1))\n//    STB_TEXTEDIT_LAYOUTROW(&r,obj,n)  returns the results of laying out a line of characters\n//                                        starting from character #n (see discussion below)\n//    STB_TEXTEDIT_GETWIDTH(obj,n,i)    returns the pixel delta from the xpos of the i'th character\n//                                        to the xpos of the i+1'th char for a line of characters\n//                                        starting at character #n (i.e. accounts for kerning\n//                                        with previous char)\n//    STB_TEXTEDIT_KEYTOTEXT(k)         maps a keyboard input to an insertable character\n//                                        (return type is int, -1 means not valid to insert)\n//    STB_TEXTEDIT_GETCHAR(obj,i)       returns the i'th character of obj, 0-based\n//    STB_TEXTEDIT_NEWLINE              the character returned by _GETCHAR() we recognize\n//                                        as manually wordwrapping for end-of-line positioning\n//\n//    STB_TEXTEDIT_DELETECHARS(obj,i,n)      delete n characters starting at i\n//    STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n)   insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*)\n//\n//    STB_TEXTEDIT_K_SHIFT       a power of two that is or'd in to a keyboard input to represent the shift key\n//\n//    STB_TEXTEDIT_K_LEFT        keyboard input to move cursor left\n//    STB_TEXTEDIT_K_RIGHT       keyboard input to move cursor right\n//    STB_TEXTEDIT_K_UP          keyboard input to move cursor up\n//    STB_TEXTEDIT_K_DOWN        keyboard input to move cursor down\n//    STB_TEXTEDIT_K_PGUP        keyboard input to move cursor up a page\n//    STB_TEXTEDIT_K_PGDOWN      keyboard input to move cursor down a page\n//    STB_TEXTEDIT_K_LINESTART   keyboard input to move cursor to start of line  // e.g. HOME\n//    STB_TEXTEDIT_K_LINEEND     keyboard input to move cursor to end of line    // e.g. END\n//    STB_TEXTEDIT_K_TEXTSTART   keyboard input to move cursor to start of text  // e.g. ctrl-HOME\n//    STB_TEXTEDIT_K_TEXTEND     keyboard input to move cursor to end of text    // e.g. ctrl-END\n//    STB_TEXTEDIT_K_DELETE      keyboard input to delete selection or character under cursor\n//    STB_TEXTEDIT_K_BACKSPACE   keyboard input to delete selection or character left of cursor\n//    STB_TEXTEDIT_K_UNDO        keyboard input to perform undo\n//    STB_TEXTEDIT_K_REDO        keyboard input to perform redo\n//\n// Optional:\n//    STB_TEXTEDIT_K_INSERT              keyboard input to toggle insert mode\n//    STB_TEXTEDIT_IS_SPACE(ch)          true if character is whitespace (e.g. 'isspace'),\n//                                          required for default WORDLEFT/WORDRIGHT handlers\n//    STB_TEXTEDIT_MOVEWORDLEFT(obj,i)   custom handler for WORDLEFT, returns index to move cursor to\n//    STB_TEXTEDIT_MOVEWORDRIGHT(obj,i)  custom handler for WORDRIGHT, returns index to move cursor to\n//    STB_TEXTEDIT_K_WORDLEFT            keyboard input to move cursor left one word // e.g. ctrl-LEFT\n//    STB_TEXTEDIT_K_WORDRIGHT           keyboard input to move cursor right one word // e.g. ctrl-RIGHT\n//    STB_TEXTEDIT_K_LINESTART2          secondary keyboard input to move cursor to start of line\n//    STB_TEXTEDIT_K_LINEEND2            secondary keyboard input to move cursor to end of line\n//    STB_TEXTEDIT_K_TEXTSTART2          secondary keyboard input to move cursor to start of text\n//    STB_TEXTEDIT_K_TEXTEND2            secondary keyboard input to move cursor to end of text\n//\n// Keyboard input must be encoded as a single integer value; e.g. a character code\n// and some bitflags that represent shift states. to simplify the interface, SHIFT must\n// be a bitflag, so we can test the shifted state of cursor movements to allow selection,\n// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.\n//\n// You can encode other things, such as CONTROL or ALT, in additional bits, and\n// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example,\n// my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN\n// bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit,\n// and I pass both WM_KEYDOWN and WM_CHAR events to the \"key\" function in the\n// API below. The control keys will only match WM_KEYDOWN events because of the\n// keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN\n// bit so it only decodes WM_CHAR events.\n//\n// STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed\n// row of characters assuming they start on the i'th character--the width and\n// the height and the number of characters consumed. This allows this library\n// to traverse the entire layout incrementally. You need to compute word-wrapping\n// here.\n//\n// Each textfield keeps its own insert mode state, which is not how normal\n// applications work. To keep an app-wide insert mode, update/copy the\n// \"insert_mode\" field of STB_TexteditState before/after calling API functions.\n//\n// API\n//\n//    void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line)\n//\n//    void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)\n//    void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)\n//    int  stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)\n//    int  stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)\n//    void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)\n//\n//    Each of these functions potentially updates the string and updates the\n//    state.\n//\n//      initialize_state:\n//          set the textedit state to a known good default state when initially\n//          constructing the textedit.\n//\n//      click:\n//          call this with the mouse x,y on a mouse down; it will update the cursor\n//          and reset the selection start/end to the cursor point. the x,y must\n//          be relative to the text widget, with (0,0) being the top left.\n//\n//      drag:\n//          call this with the mouse x,y on a mouse drag/up; it will update the\n//          cursor and the selection end point\n//\n//      cut:\n//          call this to delete the current selection; returns true if there was\n//          one. you should FIRST copy the current selection to the system paste buffer.\n//          (To copy, just copy the current selection out of the string yourself.)\n//\n//      paste:\n//          call this to paste text at the current cursor point or over the current\n//          selection if there is one.\n//\n//      key:\n//          call this for keyboard inputs sent to the textfield. you can use it\n//          for \"key down\" events or for \"translated\" key events. if you need to\n//          do both (as in Win32), or distinguish Unicode characters from control\n//          inputs, set a high bit to distinguish the two; then you can define the\n//          various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit\n//          set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is\n//          clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to\n//          anything other type you wante before including.\n//\n//\n//   When rendering, you can read the cursor position and selection state from\n//   the STB_TexteditState.\n//\n//\n// Notes:\n//\n// This is designed to be usable in IMGUI, so it allows for the possibility of\n// running in an IMGUI that has NOT cached the multi-line layout. For this\n// reason, it provides an interface that is compatible with computing the\n// layout incrementally--we try to make sure we make as few passes through\n// as possible. (For example, to locate the mouse pointer in the text, we\n// could define functions that return the X and Y positions of characters\n// and binary search Y and then X, but if we're doing dynamic layout this\n// will run the layout algorithm many times, so instead we manually search\n// forward in one pass. Similar logic applies to e.g. up-arrow and\n// down-arrow movement.)\n//\n// If it's run in a widget that *has* cached the layout, then this is less\n// efficient, but it's not horrible on modern computers. But you wouldn't\n// want to edit million-line files with it.\n\n////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////\n////\n////   Header-file mode\n////\n////\n\n#ifndef INCLUDE_STB_TEXTEDIT_H\n#define INCLUDE_STB_TEXTEDIT_H\n\n////////////////////////////////////////////////////////////////////////\n//\n//     STB_TexteditState\n//\n// Definition of STB_TexteditState which you should store\n// per-textfield; it includes cursor position, selection state,\n// and undo state.\n//\n\n#ifndef STB_TEXTEDIT_UNDOSTATECOUNT\n#define STB_TEXTEDIT_UNDOSTATECOUNT   99\n#endif\n#ifndef STB_TEXTEDIT_UNDOCHARCOUNT\n#define STB_TEXTEDIT_UNDOCHARCOUNT   999\n#endif\n#ifndef STB_TEXTEDIT_CHARTYPE\n#define STB_TEXTEDIT_CHARTYPE        int\n#endif\n#ifndef STB_TEXTEDIT_POSITIONTYPE\n#define STB_TEXTEDIT_POSITIONTYPE    int\n#endif\n\ntypedef struct\n{\n\t// private data\n\tSTB_TEXTEDIT_POSITIONTYPE  where;\n\tSTB_TEXTEDIT_POSITIONTYPE  insert_length;\n\tSTB_TEXTEDIT_POSITIONTYPE  delete_length;\n\tint                        char_storage;\n} StbUndoRecord;\n\ntypedef struct\n{\n\t// private data\n\tStbUndoRecord          undo_rec[STB_TEXTEDIT_UNDOSTATECOUNT];\n\tSTB_TEXTEDIT_CHARTYPE  undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];\n\tshort undo_point, redo_point;\n\tint undo_char_point, redo_char_point;\n} StbUndoState;\n\ntypedef struct\n{\n\t/////////////////////\n\t//\n\t// public data\n\t//\n\n\tint cursor;\n\t// position of the text cursor within the string\n\n\tint select_start;          // selection start point\n\tint select_end;\n\t// selection start and end point in characters; if equal, no selection.\n\t// note that start may be less than or greater than end (e.g. when\n\t// dragging the mouse, start is where the initial click was, and you\n\t// can drag in either direction)\n\n\tunsigned char insert_mode;\n\t// each textfield keeps its own insert mode state. to keep an app-wide\n\t// insert mode, copy this value in/out of the app state\n\n\tint row_count_per_page;\n\t// page size in number of row.\n\t// this value MUST be set to >0 for pageup or pagedown in multilines documents.\n\n\t/////////////////////\n\t//\n\t// private data\n\t//\n\tunsigned char cursor_at_end_of_line; // not implemented yet\n\tunsigned char initialized;\n\tunsigned char has_preferred_x;\n\tunsigned char single_line;\n\tunsigned char padding1, padding2, padding3;\n\tfloat preferred_x; // this determines where the cursor up/down tries to seek to along x\n\tStbUndoState undostate;\n} STB_TexteditState;\n\n////////////////////////////////////////////////////////////////////////\n//\n//     StbTexteditRow\n//\n// Result of layout query, used by stb_textedit to determine where\n// the text in each row is.\n\n// result of layout query\ntypedef struct\n{\n\tfloat x0, x1;             // starting x location, end x location (allows for align=right, etc)\n\tfloat baseline_y_delta;  // position of baseline relative to previous row's baseline\n\tfloat ymin, ymax;         // height of row above and below baseline\n\tint num_chars;\n} StbTexteditRow;\n#endif //INCLUDE_STB_TEXTEDIT_H\n\n////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////\n////\n////   Implementation mode\n////\n////\n\n// implementation isn't include-guarded, since it might have indirectly\n// included just the \"header\" portion\n#ifdef STB_TEXTEDIT_IMPLEMENTATION\n\n#ifndef STB_TEXTEDIT_memmove\n#include <string.h>\n#define STB_TEXTEDIT_memmove memmove\n#endif\n\n/////////////////////////////////////////////////////////////////////////////\n//\n//      Mouse input handling\n//\n\n// traverse the layout to locate the nearest character to a display position\nstatic int stb_text_locate_coord(STB_TEXTEDIT_STRING* str, float x, float y)\n{\n\tStbTexteditRow r;\n\tint n = STB_TEXTEDIT_STRINGLEN(str);\n\tfloat base_y = 0, prev_x;\n\tint i = 0, k;\n\n\tr.x0 = r.x1 = 0;\n\tr.ymin = r.ymax = 0;\n\tr.num_chars = 0;\n\n\t// search rows to find one that straddles 'y'\n\twhile (i < n) {\n\t\tSTB_TEXTEDIT_LAYOUTROW(&r, str, i);\n\t\tif (r.num_chars <= 0)\n\t\t\treturn n;\n\n\t\tif (i == 0 && y < base_y + r.ymin)\n\t\t\treturn 0;\n\n\t\tif (y < base_y + r.ymax)\n\t\t\tbreak;\n\n\t\ti += r.num_chars;\n\t\tbase_y += r.baseline_y_delta;\n\t}\n\n\t// below all text, return 'after' last character\n\tif (i >= n)\n\t\treturn n;\n\n\t// check if it's before the beginning of the line\n\tif (x < r.x0)\n\t\treturn i;\n\n\t// check if it's before the end of the line\n\tif (x < r.x1) {\n\t\t// search characters in row for one that straddles 'x'\n\t\tprev_x = r.x0;\n\t\tfor (k = 0; k < r.num_chars; ++k) {\n\t\t\tfloat w = STB_TEXTEDIT_GETWIDTH(str, i, k);\n\t\t\tif (x < prev_x + w) {\n\t\t\t\tif (x < prev_x + w / 2)\n\t\t\t\t\treturn k + i;\n\t\t\t\telse\n\t\t\t\t\treturn k + i + 1;\n\t\t\t}\n\t\t\tprev_x += w;\n\t\t}\n\t\t// shouldn't happen, but if it does, fall through to end-of-line case\n\t}\n\n\t// if the last character is a newline, return that. otherwise return 'after' the last character\n\tif (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) == STB_TEXTEDIT_NEWLINE)\n\t\treturn i + r.num_chars - 1;\n\telse\n\t\treturn i + r.num_chars;\n}\n\n// API click: on mouse down, move the cursor to the clicked location, and reset the selection\nstatic void stb_textedit_click(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, float x, float y)\n{\n\t// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse\n\t// goes off the top or bottom of the text\n\tif (state->single_line)\n\t{\n\t\tStbTexteditRow r;\n\t\tSTB_TEXTEDIT_LAYOUTROW(&r, str, 0);\n\t\ty = r.ymin;\n\t}\n\n\tstate->cursor = stb_text_locate_coord(str, x, y);\n\tstate->select_start = state->cursor;\n\tstate->select_end = state->cursor;\n\tstate->has_preferred_x = 0;\n}\n\n// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location\nstatic void stb_textedit_drag(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, float x, float y)\n{\n\tint p = 0;\n\n\t// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse\n\t// goes off the top or bottom of the text\n\tif (state->single_line)\n\t{\n\t\tStbTexteditRow r;\n\t\tSTB_TEXTEDIT_LAYOUTROW(&r, str, 0);\n\t\ty = r.ymin;\n\t}\n\n\tif (state->select_start == state->select_end)\n\t\tstate->select_start = state->cursor;\n\n\tp = stb_text_locate_coord(str, x, y);\n\tstate->cursor = state->select_end = p;\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n//      Keyboard input handling\n//\n\n// forward declarations\nstatic void stb_text_undo(STB_TEXTEDIT_STRING* str, STB_TexteditState* state);\nstatic void stb_text_redo(STB_TEXTEDIT_STRING* str, STB_TexteditState* state);\nstatic void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, int where, int length);\nstatic void stb_text_makeundo_insert(STB_TexteditState* state, int where, int length);\nstatic void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, int where, int old_length, int new_length);\n\ntypedef struct\n{\n\tfloat x, y;    // position of n'th character\n\tfloat height; // height of line\n\tint first_char, length; // first char of row, and length\n\tint prev_first;  // first char of previous row\n} StbFindState;\n\n// find the x/y location of a character, and remember info about the previous row in\n// case we get a move-up event (for page up, we'll have to rescan)\nstatic void stb_textedit_find_charpos(StbFindState* find, STB_TEXTEDIT_STRING* str, int n, int single_line)\n{\n\tStbTexteditRow r;\n\tint prev_start = 0;\n\tint z = STB_TEXTEDIT_STRINGLEN(str);\n\tint i = 0, first;\n\n\tif (n == z && single_line) {\n\t\t// special case if it's at the end (may not be needed?)\n\t\tSTB_TEXTEDIT_LAYOUTROW(&r, str, 0);\n\t\tfind->y = 0;\n\t\tfind->first_char = 0;\n\t\tfind->length = z;\n\t\tfind->height = r.ymax - r.ymin;\n\t\tfind->x = r.x1;\n\t\treturn;\n\t}\n\n\t// search rows to find the one that straddles character n\n\tfind->y = 0;\n\n\tfor (;;) {\n\t\tSTB_TEXTEDIT_LAYOUTROW(&r, str, i);\n\t\tif (n < i + r.num_chars)\n\t\t\tbreak;\n\t\tif (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE)  // [DEAR IMGUI] special handling for last line\n\t\t\tbreak;   // [DEAR IMGUI]\n\t\tprev_start = i;\n\t\ti += r.num_chars;\n\t\tfind->y += r.baseline_y_delta;\n\t\tif (i == z) // [DEAR IMGUI]\n\t\t\tbreak;   // [DEAR IMGUI]\n\t}\n\n\tfind->first_char = first = i;\n\tfind->length = r.num_chars;\n\tfind->height = r.ymax - r.ymin;\n\tfind->prev_first = prev_start;\n\n\t// now scan to find xpos\n\tfind->x = r.x0;\n\tfor (i = 0; first + i < n; ++i)\n\t\tfind->x += STB_TEXTEDIT_GETWIDTH(str, first, i);\n}\n\n#define STB_TEXT_HAS_SELECTION(s)   ((s)->select_start != (s)->select_end)\n\n// make the selection/cursor state valid if client altered the string\nstatic void stb_textedit_clamp(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tint n = STB_TEXTEDIT_STRINGLEN(str);\n\tif (STB_TEXT_HAS_SELECTION(state)) {\n\t\tif (state->select_start > n) state->select_start = n;\n\t\tif (state->select_end > n) state->select_end = n;\n\t\t// if clamping forced them to be equal, move the cursor to match\n\t\tif (state->select_start == state->select_end)\n\t\t\tstate->cursor = state->select_start;\n\t}\n\tif (state->cursor > n) state->cursor = n;\n}\n\n// delete characters while updating undo\nstatic void stb_textedit_delete(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, int where, int len)\n{\n\tstb_text_makeundo_delete(str, state, where, len);\n\tSTB_TEXTEDIT_DELETECHARS(str, where, len);\n\tstate->has_preferred_x = 0;\n}\n\n// delete the section\nstatic void stb_textedit_delete_selection(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tstb_textedit_clamp(str, state);\n\tif (STB_TEXT_HAS_SELECTION(state)) {\n\t\tif (state->select_start < state->select_end) {\n\t\t\tstb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);\n\t\t\tstate->select_end = state->cursor = state->select_start;\n\t\t}\n\t\telse {\n\t\t\tstb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);\n\t\t\tstate->select_start = state->cursor = state->select_end;\n\t\t}\n\t\tstate->has_preferred_x = 0;\n\t}\n}\n\n// canoncialize the selection so start <= end\nstatic void stb_textedit_sortselection(STB_TexteditState* state)\n{\n\tif (state->select_end < state->select_start) {\n\t\tint temp = state->select_end;\n\t\tstate->select_end = state->select_start;\n\t\tstate->select_start = temp;\n\t}\n}\n\n// move cursor to first character of selection\nstatic void stb_textedit_move_to_first(STB_TexteditState* state)\n{\n\tif (STB_TEXT_HAS_SELECTION(state)) {\n\t\tstb_textedit_sortselection(state);\n\t\tstate->cursor = state->select_start;\n\t\tstate->select_end = state->select_start;\n\t\tstate->has_preferred_x = 0;\n\t}\n}\n\n// move cursor to last character of selection\nstatic void stb_textedit_move_to_last(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tif (STB_TEXT_HAS_SELECTION(state)) {\n\t\tstb_textedit_sortselection(state);\n\t\tstb_textedit_clamp(str, state);\n\t\tstate->cursor = state->select_end;\n\t\tstate->select_start = state->select_end;\n\t\tstate->has_preferred_x = 0;\n\t}\n}\n\n#ifdef STB_TEXTEDIT_IS_SPACE\nstatic int is_word_boundary(STB_TEXTEDIT_STRING* str, int idx)\n{\n\treturn idx > 0 ? (STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;\n}\n\n#ifndef STB_TEXTEDIT_MOVEWORDLEFT\nstatic int stb_textedit_move_to_word_previous(STB_TEXTEDIT_STRING* str, int c)\n{\n\t--c; // always move at least one character\n\twhile (c >= 0 && !is_word_boundary(str, c))\n\t\t--c;\n\n\tif (c < 0)\n\t\tc = 0;\n\n\treturn c;\n}\n#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous\n#endif\n\n#ifndef STB_TEXTEDIT_MOVEWORDRIGHT\nstatic int stb_textedit_move_to_word_next(STB_TEXTEDIT_STRING* str, int c)\n{\n\tconst int len = STB_TEXTEDIT_STRINGLEN(str);\n\t++c; // always move at least one character\n\twhile (c < len && !is_word_boundary(str, c))\n\t\t++c;\n\n\tif (c > len)\n\t\tc = len;\n\n\treturn c;\n}\n#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next\n#endif\n\n#endif\n\n// update selection and cursor to match each other\nstatic void stb_textedit_prep_selection_at_cursor(STB_TexteditState* state)\n{\n\tif (!STB_TEXT_HAS_SELECTION(state))\n\t\tstate->select_start = state->select_end = state->cursor;\n\telse\n\t\tstate->cursor = state->select_end;\n}\n\n// API cut: delete selection\nstatic int stb_textedit_cut(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tif (STB_TEXT_HAS_SELECTION(state)) {\n\t\tstb_textedit_delete_selection(str, state); // implicitly clamps\n\t\tstate->has_preferred_x = 0;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n// API paste: replace existing selection with passed-in text\nstatic int stb_textedit_paste_internal(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE* text, int len)\n{\n\t// if there's a selection, the paste should delete it\n\tstb_textedit_clamp(str, state);\n\tstb_textedit_delete_selection(str, state);\n\t// try to insert the characters\n\tif (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {\n\t\tstb_text_makeundo_insert(state, state->cursor, len);\n\t\tstate->cursor += len;\n\t\tstate->has_preferred_x = 0;\n\t\treturn 1;\n\t}\n\t// note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details)\n\treturn 0;\n}\n\n#ifndef STB_TEXTEDIT_KEYTYPE\n#define STB_TEXTEDIT_KEYTYPE int\n#endif\n\n// API key: process a keyboard input\nstatic void stb_textedit_key(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, STB_TEXTEDIT_KEYTYPE key)\n{\nretry:\n\tswitch (key) {\n\tdefault: {\n\t\tint c = STB_TEXTEDIT_KEYTOTEXT(key);\n\t\tif (c > 0) {\n\t\t\tSTB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c;\n\n\t\t\t// can't add newline in single-line mode\n\t\t\tif (c == '\\n' && state->single_line)\n\t\t\t\tbreak;\n\n\t\t\tif (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {\n\t\t\t\tstb_text_makeundo_replace(str, state, state->cursor, 1, 1);\n\t\t\t\tSTB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);\n\t\t\t\tif (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {\n\t\t\t\t\t++state->cursor;\n\t\t\t\t\tstate->has_preferred_x = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstb_textedit_delete_selection(str, state); // implicitly clamps\n\t\t\t\tif (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {\n\t\t\t\t\tstb_text_makeundo_insert(state, state->cursor, 1);\n\t\t\t\t\t++state->cursor;\n\t\t\t\t\tstate->has_preferred_x = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n#ifdef STB_TEXTEDIT_K_INSERT\n\tcase STB_TEXTEDIT_K_INSERT:\n\t\tstate->insert_mode = !state->insert_mode;\n\t\tbreak;\n#endif\n\n\tcase STB_TEXTEDIT_K_UNDO:\n\t\tstb_text_undo(str, state);\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_REDO:\n\t\tstb_text_redo(str, state);\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_LEFT:\n\t\t// if currently there's a selection, move cursor to start of selection\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_first(state);\n\t\telse\n\t\t\tif (state->cursor > 0)\n\t\t\t\t--state->cursor;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_RIGHT:\n\t\t// if currently there's a selection, move cursor to end of selection\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_last(str, state);\n\t\telse\n\t\t\t++state->cursor;\n\t\tstb_textedit_clamp(str, state);\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\t// move selection left\n\t\tif (state->select_end > 0)\n\t\t\t--state->select_end;\n\t\tstate->cursor = state->select_end;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_MOVEWORDLEFT\n\tcase STB_TEXTEDIT_K_WORDLEFT:\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_first(state);\n\t\telse {\n\t\t\tstate->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);\n\t\t\tstb_textedit_clamp(str, state);\n\t\t}\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:\n\t\tif (!STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_prep_selection_at_cursor(state);\n\n\t\tstate->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);\n\t\tstate->select_end = state->cursor;\n\n\t\tstb_textedit_clamp(str, state);\n\t\tbreak;\n#endif\n\n#ifdef STB_TEXTEDIT_MOVEWORDRIGHT\n\tcase STB_TEXTEDIT_K_WORDRIGHT:\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_last(str, state);\n\t\telse {\n\t\t\tstate->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);\n\t\t\tstb_textedit_clamp(str, state);\n\t\t}\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:\n\t\tif (!STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_prep_selection_at_cursor(state);\n\n\t\tstate->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);\n\t\tstate->select_end = state->cursor;\n\n\t\tstb_textedit_clamp(str, state);\n\t\tbreak;\n#endif\n\n\tcase STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\t// move selection right\n\t\t++state->select_end;\n\t\tstb_textedit_clamp(str, state);\n\t\tstate->cursor = state->select_end;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_DOWN:\n\tcase STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:\n\tcase STB_TEXTEDIT_K_PGDOWN:\n\tcase STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {\n\t\tStbFindState find;\n\t\tStbTexteditRow row;\n\t\tint i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;\n\t\tint is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;\n\t\tint row_count = is_page ? state->row_count_per_page : 1;\n\n\t\tif (!is_page && state->single_line) {\n\t\t\t// on windows, up&down in single-line behave like left&right\n\t\t\tkey = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);\n\t\t\tgoto retry;\n\t\t}\n\n\t\tif (sel)\n\t\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\telse if (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_last(str, state);\n\n\t\t// compute current position of cursor point\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_find_charpos(&find, str, state->cursor, state->single_line);\n\n\t\tfor (j = 0; j < row_count; ++j) {\n\t\t\tfloat x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n\t\t\tint start = find.first_char + find.length;\n\n\t\t\tif (find.length == 0)\n\t\t\t\tbreak;\n\n\t\t\t// [DEAR IMGUI]\n\t\t\t// going down while being on the last line shouldn't bring us to that line end\n\t\t\tif (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)\n\t\t\t\tbreak;\n\n\t\t\t// now find character position down a row\n\t\t\tstate->cursor = start;\n\t\t\tSTB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);\n\t\t\tx = row.x0;\n\t\t\tfor (i = 0; i < row.num_chars; ++i) {\n\t\t\t\tfloat dx = STB_TEXTEDIT_GETWIDTH(str, start, i);\n#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE\n\t\t\t\tif (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)\n\t\t\t\t\tbreak;\n#endif\n\t\t\t\tx += dx;\n\t\t\t\tif (x > goal_x)\n\t\t\t\t\tbreak;\n\t\t\t\t++state->cursor;\n\t\t\t}\n\t\t\tstb_textedit_clamp(str, state);\n\n\t\t\tstate->has_preferred_x = 1;\n\t\t\tstate->preferred_x = goal_x;\n\n\t\t\tif (sel)\n\t\t\t\tstate->select_end = state->cursor;\n\n\t\t\t// go to next line\n\t\t\tfind.first_char = find.first_char + find.length;\n\t\t\tfind.length = row.num_chars;\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase STB_TEXTEDIT_K_UP:\n\tcase STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:\n\tcase STB_TEXTEDIT_K_PGUP:\n\tcase STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {\n\t\tStbFindState find;\n\t\tStbTexteditRow row;\n\t\tint i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;\n\t\tint is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;\n\t\tint row_count = is_page ? state->row_count_per_page : 1;\n\n\t\tif (!is_page && state->single_line) {\n\t\t\t// on windows, up&down become left&right\n\t\t\tkey = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);\n\t\t\tgoto retry;\n\t\t}\n\n\t\tif (sel)\n\t\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\telse if (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_move_to_first(state);\n\n\t\t// compute current position of cursor point\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_find_charpos(&find, str, state->cursor, state->single_line);\n\n\t\tfor (j = 0; j < row_count; ++j) {\n\t\t\tfloat  x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n\n\t\t\t// can only go up if there's a previous row\n\t\t\tif (find.prev_first == find.first_char)\n\t\t\t\tbreak;\n\n\t\t\t// now find character position up a row\n\t\t\tstate->cursor = find.prev_first;\n\t\t\tSTB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);\n\t\t\tx = row.x0;\n\t\t\tfor (i = 0; i < row.num_chars; ++i) {\n\t\t\t\tfloat dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);\n#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE\n\t\t\t\tif (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)\n\t\t\t\t\tbreak;\n#endif\n\t\t\t\tx += dx;\n\t\t\t\tif (x > goal_x)\n\t\t\t\t\tbreak;\n\t\t\t\t++state->cursor;\n\t\t\t}\n\t\t\tstb_textedit_clamp(str, state);\n\n\t\t\tstate->has_preferred_x = 1;\n\t\t\tstate->preferred_x = goal_x;\n\n\t\t\tif (sel)\n\t\t\t\tstate->select_end = state->cursor;\n\n\t\t\t// go to previous line\n\t\t\t// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)\n\t\t\tprev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;\n\t\t\twhile (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)\n\t\t\t\t--prev_scan;\n\t\t\tfind.first_char = find.prev_first;\n\t\t\tfind.prev_first = prev_scan;\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase STB_TEXTEDIT_K_DELETE:\n\tcase STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_delete_selection(str, state);\n\t\telse {\n\t\t\tint n = STB_TEXTEDIT_STRINGLEN(str);\n\t\t\tif (state->cursor < n)\n\t\t\t\tstb_textedit_delete(str, state, state->cursor, 1);\n\t\t}\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n\tcase STB_TEXTEDIT_K_BACKSPACE:\n\tcase STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:\n\t\tif (STB_TEXT_HAS_SELECTION(state))\n\t\t\tstb_textedit_delete_selection(str, state);\n\t\telse {\n\t\t\tstb_textedit_clamp(str, state);\n\t\t\tif (state->cursor > 0) {\n\t\t\t\tstb_textedit_delete(str, state, state->cursor - 1, 1);\n\t\t\t\t--state->cursor;\n\t\t\t}\n\t\t}\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_TEXTSTART2\n\tcase STB_TEXTEDIT_K_TEXTSTART2:\n#endif\n\tcase STB_TEXTEDIT_K_TEXTSTART:\n\t\tstate->cursor = state->select_start = state->select_end = 0;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_TEXTEND2\n\tcase STB_TEXTEDIT_K_TEXTEND2:\n#endif\n\tcase STB_TEXTEDIT_K_TEXTEND:\n\t\tstate->cursor = STB_TEXTEDIT_STRINGLEN(str);\n\t\tstate->select_start = state->select_end = 0;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_TEXTSTART2\n\tcase STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:\n#endif\n\tcase STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\tstate->cursor = state->select_end = 0;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_TEXTEND2\n\tcase STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:\n#endif\n\tcase STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\tstate->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_LINESTART2\n\tcase STB_TEXTEDIT_K_LINESTART2:\n#endif\n\tcase STB_TEXTEDIT_K_LINESTART:\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_move_to_first(state);\n\t\tif (state->single_line)\n\t\t\tstate->cursor = 0;\n\t\telse while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)\n\t\t\t--state->cursor;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_LINEEND2\n\tcase STB_TEXTEDIT_K_LINEEND2:\n#endif\n\tcase STB_TEXTEDIT_K_LINEEND: {\n\t\tint n = STB_TEXTEDIT_STRINGLEN(str);\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_move_to_first(state);\n\t\tif (state->single_line)\n\t\t\tstate->cursor = n;\n\t\telse while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)\n\t\t\t++state->cursor;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\t}\n\n#ifdef STB_TEXTEDIT_K_LINESTART2\n\tcase STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:\n#endif\n\tcase STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\tif (state->single_line)\n\t\t\tstate->cursor = 0;\n\t\telse while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)\n\t\t\t--state->cursor;\n\t\tstate->select_end = state->cursor;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\n#ifdef STB_TEXTEDIT_K_LINEEND2\n\tcase STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:\n#endif\n\tcase STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {\n\t\tint n = STB_TEXTEDIT_STRINGLEN(str);\n\t\tstb_textedit_clamp(str, state);\n\t\tstb_textedit_prep_selection_at_cursor(state);\n\t\tif (state->single_line)\n\t\t\tstate->cursor = n;\n\t\telse while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)\n\t\t\t++state->cursor;\n\t\tstate->select_end = state->cursor;\n\t\tstate->has_preferred_x = 0;\n\t\tbreak;\n\t}\n\t}\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n//      Undo processing\n//\n// @OPTIMIZE: the undo/redo buffer should be circular\n\nstatic void stb_textedit_flush_redo(StbUndoState* state)\n{\n\tstate->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;\n\tstate->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;\n}\n\n// discard the oldest entry in the undo list\nstatic void stb_textedit_discard_undo(StbUndoState* state)\n{\n\tif (state->undo_point > 0) {\n\t\t// if the 0th undo state has characters, clean those up\n\t\tif (state->undo_rec[0].char_storage >= 0) {\n\t\t\tint n = state->undo_rec[0].insert_length, i;\n\t\t\t// delete n characters from all other records\n\t\t\tstate->undo_char_point -= n;\n\t\t\tSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t)(state->undo_char_point * sizeof(STB_TEXTEDIT_CHARTYPE)));\n\t\t\tfor (i = 0; i < state->undo_point; ++i)\n\t\t\t\tif (state->undo_rec[i].char_storage >= 0)\n\t\t\t\t\tstate->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it\n\t\t}\n\t\t--state->undo_point;\n\t\tSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (size_t)(state->undo_point * sizeof(state->undo_rec[0])));\n\t}\n}\n\n// discard the oldest entry in the redo list--it's bad if this\n// ever happens, but because undo & redo have to store the actual\n// characters in different cases, the redo character buffer can\n// fill up even though the undo buffer didn't\nstatic void stb_textedit_discard_redo(StbUndoState* state)\n{\n\tint k = STB_TEXTEDIT_UNDOSTATECOUNT - 1;\n\n\tif (state->redo_point <= k) {\n\t\t// if the k'th undo state has characters, clean those up\n\t\tif (state->undo_rec[k].char_storage >= 0) {\n\t\t\tint n = state->undo_rec[k].insert_length, i;\n\t\t\t// move the remaining redo character data to the end of the buffer\n\t\t\tstate->redo_char_point += n;\n\t\t\tSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point - n, (size_t)((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point) * sizeof(STB_TEXTEDIT_CHARTYPE)));\n\t\t\t// adjust the position of all the other records to account for above memmove\n\t\t\tfor (i = state->redo_point; i < k; ++i)\n\t\t\t\tif (state->undo_rec[i].char_storage >= 0)\n\t\t\t\t\tstate->undo_rec[i].char_storage += n;\n\t\t}\n\t\t// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'\n\t\t// [DEAR IMGUI]\n\t\tsize_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));\n\t\tconst char* buf_begin = (char*)state->undo_rec; (void)buf_begin;\n\t\tconst char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;\n\t\tIM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);\n\t\tIM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);\n\t\tSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point + 1, state->undo_rec + state->redo_point, move_size);\n\n\t\t// now move redo_point to point to the new one\n\t\t++state->redo_point;\n\t}\n}\n\nstatic StbUndoRecord* stb_text_create_undo_record(StbUndoState* state, int numchars)\n{\n\t// any time we create a new undo record, we discard redo\n\tstb_textedit_flush_redo(state);\n\n\t// if we have no free records, we have to make room, by sliding the\n\t// existing records down\n\tif (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)\n\t\tstb_textedit_discard_undo(state);\n\n\t// if the characters to store won't possibly fit in the buffer, we can't undo\n\tif (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {\n\t\tstate->undo_point = 0;\n\t\tstate->undo_char_point = 0;\n\t\treturn NULL;\n\t}\n\n\t// if we don't have enough free characters in the buffer, we have to make room\n\twhile (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)\n\t\tstb_textedit_discard_undo(state);\n\n\treturn &state->undo_rec[state->undo_point++];\n}\n\nstatic STB_TEXTEDIT_CHARTYPE* stb_text_createundo(StbUndoState* state, int pos, int insert_len, int delete_len)\n{\n\tStbUndoRecord* r = stb_text_create_undo_record(state, insert_len);\n\tif (r == NULL)\n\t\treturn NULL;\n\n\tr->where = pos;\n\tr->insert_length = (STB_TEXTEDIT_POSITIONTYPE)insert_len;\n\tr->delete_length = (STB_TEXTEDIT_POSITIONTYPE)delete_len;\n\n\tif (insert_len == 0) {\n\t\tr->char_storage = -1;\n\t\treturn NULL;\n\t}\n\telse {\n\t\tr->char_storage = state->undo_char_point;\n\t\tstate->undo_char_point += insert_len;\n\t\treturn &state->undo_char[r->char_storage];\n\t}\n}\n\nstatic void stb_text_undo(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tStbUndoState* s = &state->undostate;\n\tStbUndoRecord u, * r;\n\tif (s->undo_point == 0)\n\t\treturn;\n\n\t// we need to do two things: apply the undo record, and create a redo record\n\tu = s->undo_rec[s->undo_point - 1];\n\tr = &s->undo_rec[s->redo_point - 1];\n\tr->char_storage = -1;\n\n\tr->insert_length = u.delete_length;\n\tr->delete_length = u.insert_length;\n\tr->where = u.where;\n\n\tif (u.delete_length) {\n\t\t// if the undo record says to delete characters, then the redo record will\n\t\t// need to re-insert the characters that get deleted, so we need to store\n\t\t// them.\n\n\t\t// there are three cases:\n\t\t//    there's enough room to store the characters\n\t\t//    characters stored for *redoing* don't leave room for redo\n\t\t//    characters stored for *undoing* don't leave room for redo\n\t\t// if the last is true, we have to bail\n\n\t\tif (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {\n\t\t\t// the undo records take up too much character space; there's no space to store the redo characters\n\t\t\tr->insert_length = 0;\n\t\t}\n\t\telse {\n\t\t\tint i;\n\n\t\t\t// there's definitely room to store the characters eventually\n\t\t\twhile (s->undo_char_point + u.delete_length > s->redo_char_point) {\n\t\t\t\t// should never happen:\n\t\t\t\tif (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)\n\t\t\t\t\treturn;\n\t\t\t\t// there's currently not enough room, so discard a redo record\n\t\t\t\tstb_textedit_discard_redo(s);\n\t\t\t}\n\t\t\tr = &s->undo_rec[s->redo_point - 1];\n\n\t\t\tr->char_storage = s->redo_char_point - u.delete_length;\n\t\t\ts->redo_char_point = s->redo_char_point - u.delete_length;\n\n\t\t\t// now save the characters\n\t\t\tfor (i = 0; i < u.delete_length; ++i)\n\t\t\t\ts->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);\n\t\t}\n\n\t\t// now we can carry out the deletion\n\t\tSTB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);\n\t}\n\n\t// check type of recorded action:\n\tif (u.insert_length) {\n\t\t// easy case: was a deletion, so we need to insert n characters\n\t\tSTB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);\n\t\ts->undo_char_point -= u.insert_length;\n\t}\n\n\tstate->cursor = u.where + u.insert_length;\n\n\ts->undo_point--;\n\ts->redo_point--;\n}\n\nstatic void stb_text_redo(STB_TEXTEDIT_STRING* str, STB_TexteditState* state)\n{\n\tStbUndoState* s = &state->undostate;\n\tStbUndoRecord* u, r;\n\tif (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)\n\t\treturn;\n\n\t// we need to do two things: apply the redo record, and create an undo record\n\tu = &s->undo_rec[s->undo_point];\n\tr = s->undo_rec[s->redo_point];\n\n\t// we KNOW there must be room for the undo record, because the redo record\n\t// was derived from an undo record\n\n\tu->delete_length = r.insert_length;\n\tu->insert_length = r.delete_length;\n\tu->where = r.where;\n\tu->char_storage = -1;\n\n\tif (r.delete_length) {\n\t\t// the redo record requires us to delete characters, so the undo record\n\t\t// needs to store the characters\n\n\t\tif (s->undo_char_point + u->insert_length > s->redo_char_point) {\n\t\t\tu->insert_length = 0;\n\t\t\tu->delete_length = 0;\n\t\t}\n\t\telse {\n\t\t\tint i;\n\t\t\tu->char_storage = s->undo_char_point;\n\t\t\ts->undo_char_point = s->undo_char_point + u->insert_length;\n\n\t\t\t// now save the characters\n\t\t\tfor (i = 0; i < u->insert_length; ++i)\n\t\t\t\ts->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);\n\t\t}\n\n\t\tSTB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);\n\t}\n\n\tif (r.insert_length) {\n\t\t// easy case: need to insert n characters\n\t\tSTB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);\n\t\ts->redo_char_point += r.insert_length;\n\t}\n\n\tstate->cursor = r.where + r.insert_length;\n\n\ts->undo_point++;\n\ts->redo_point++;\n}\n\nstatic void stb_text_makeundo_insert(STB_TexteditState* state, int where, int length)\n{\n\tstb_text_createundo(&state->undostate, where, 0, length);\n}\n\nstatic void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, int where, int length)\n{\n\tint i;\n\tSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, length, 0);\n\tif (p) {\n\t\tfor (i = 0; i < length; ++i)\n\t\t\tp[i] = STB_TEXTEDIT_GETCHAR(str, where + i);\n\t}\n}\n\nstatic void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, int where, int old_length, int new_length)\n{\n\tint i;\n\tSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, old_length, new_length);\n\tif (p) {\n\t\tfor (i = 0; i < old_length; ++i)\n\t\t\tp[i] = STB_TEXTEDIT_GETCHAR(str, where + i);\n\t}\n}\n\n// reset the state to default\nstatic void stb_textedit_clear_state(STB_TexteditState* state, int is_single_line)\n{\n\tstate->undostate.undo_point = 0;\n\tstate->undostate.undo_char_point = 0;\n\tstate->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;\n\tstate->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;\n\tstate->select_end = state->select_start = 0;\n\tstate->cursor = 0;\n\tstate->has_preferred_x = 0;\n\tstate->preferred_x = 0;\n\tstate->cursor_at_end_of_line = 0;\n\tstate->initialized = 1;\n\tstate->single_line = (unsigned char)is_single_line;\n\tstate->insert_mode = 0;\n\tstate->row_count_per_page = 0;\n}\n\n// API initialize\nstatic void stb_textedit_initialize_state(STB_TexteditState* state, int is_single_line)\n{\n\tstb_textedit_clear_state(state, is_single_line);\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\n\nstatic int stb_textedit_paste(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE const* ctext, int len)\n{\n\treturn stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE*)ctext, len);\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#endif//STB_TEXTEDIT_IMPLEMENTATION\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "KBotExt.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30406.217\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"KBotExt\", \"KBotExt\\KBotExt.vcxproj\", \"{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Debug|x64.Build.0 = Debug|x64\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Debug|x86.Build.0 = Debug|Win32\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Release|x64.ActiveCfg = Release|x64\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Release|x64.Build.0 = Release|x64\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Release|x86.ActiveCfg = Release|Win32\n\t\t{1F8647C7-3A8D-4AA4-9F22-778FFAD47C75}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {9903E8E7-8C40-4C92-91AD-B447164BBFAF}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# ⚠ KBotExt is bannable by Vanguard. [Read more](https://github.com/KebsCS/KBotExt/issues/252)\n\n![Example](https://i.imgur.com/aLQOwy4.png)\n\n[More screenshots](https://imgur.com/a/Z5LRbV0)\n\n## Download\n- [Stable release](https://github.com/KebsCS/KBotExt/releases/latest) (You will be notified when there's a new release)\n- [Prerelease](https://github.com/KebsCS/KBotExt/releases/tag/prerelease)\n\n## Features\n* Works every patch\n* Free ARAM boost\n* Launch multiple clients\n* Language changer\n* Start any lobby/game\n* Custom bots difficulty\n* The fastest instalock, auto accept, instant message and auto ban\n* Automatically pick a secondary, or dodge if your champion is banned\n* Instantly mute everyone in champion select\n* Dodge lobbies without closing the client\n* Mass invite all friends to lobby\n* Multi-search op.gg/u.gg/poro.gg etc. with all players in a champ select (works in ranked - lobby reveal)\n* Set the best runes for your selected champion from op.gg (works even when runes aren't unlocked)\n* Shows which map side you are on, in all gamemodes\n* Create lobbies for hidden gamemodes\n* Force Jungle/Lane on Nexus Blitz\n* Set custom icon/background/status/rank/mastery/challenges visible for everyone\n* Set glitched or empty challenge badges (tokens)\n* Set invisible profile/lobby banner\n* Info of any player using his nickname or id\n* List of champions/skins with all info and ability to sort them\n* Force close the client instantly\n* Mass delete all friends sorted by folders\n* Accept or delete all friend requests\n* Check the email of any account\n* Set custom in-game minimap scale\n* Disenchant any loot you want with 1 click (mass disenchant)\n* Champion name to id lookup\n* Send any custom request to LCU, Riot Client, RTMP, Store and Ledge\n* Stream proof\n* IFEO debugger for using HTTP debuggers (Fiddler, Charles, etc.)\n* Log cleaner\n* Ban checker\n* Automatically saves your preferences\n* Unicode support and customizable window size\n* 1 click login with automated client open\n* Force client to run without admin\n* (Patched) Play any champion/skin for free (Refund exploit)\n* (Patched) Free skin and free champion (Riot Girl Tristana)\n\n## Development\n\n- **Installing required libraries**\n  1. Install [GIT for windows](https://git-scm.com/download/win)\n  2. Open Windows Command Prompt (**CMD**)\n  3. Run `git clone https://github.com/microsoft/vcpkg.git`\n  4. `cd vcpkg`\n  5. `bootstrap-vcpkg.bat`\n  6. `vcpkg integrate install`\n  7. `vcpkg install freetype:x64-windows-static`\n  8. `vcpkg install cpr:x64-windows-static`\n  9. `vcpkg install jsoncpp:x64-windows-static`\n- **Building the project**\n  1. Clone the repository\n  2. Open **KBotExt.sln** in Visual Studio (Recommended Visual Studio 2022)\n  3. Set the solution platform to x64 Release\n  4. Build the project\n  5. Feel free to make a pull request with your changes :-)\n\n\n## Discord\nFeel free to ask any questions regarding this project, or league client on my [discord server](https://discord.gg/qMmPBFpj2n), although I won't be teaching you how to code there if you're a complete beginner\n"
  }
]