mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 03:32:10 +08:00
9269 lines
355 KiB
C++
9269 lines
355 KiB
C++
|
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
|
|
#include "imgui.h"
|
|
#ifndef IMGUI_DISABLE
|
|
|
|
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
#endif
|
|
#include "imgui_internal.h"
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#if defined(_MSC_VER) && _MSC_VER <= 1500
|
|
#include <stddef.h>
|
|
#else
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#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)
|
|
#define IMGUI_DISABLE_WIN32_FUNCTIONS
|
|
#endif
|
|
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#ifndef __MINGW32__
|
|
#include <Windows.h>
|
|
#else
|
|
#include <windows.h>
|
|
#endif
|
|
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
|
#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
|
|
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__APPLE__)
|
|
#include <TargetConditionals.h>
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable: 4127)
|
|
#pragma warning (disable: 4996)
|
|
#if defined(_MSC_VER) && _MSC_VER >= 1922
|
|
#pragma warning (disable: 5054)
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__clang__)
|
|
#if __has_warning("-Wunknown-warning-option")
|
|
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
|
#endif
|
|
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
|
#pragma clang diagnostic ignored "-Wfloat-equal"
|
|
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
|
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
|
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
#pragma clang diagnostic ignored "-Wformat-pedantic"
|
|
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
|
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
|
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
#elif defined(__GNUC__)
|
|
#pragma GCC diagnostic ignored "-Wpragmas"
|
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
|
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
|
#pragma GCC diagnostic ignored "-Wformat"
|
|
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
#pragma GCC diagnostic ignored "-Wconversion"
|
|
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
|
#pragma GCC diagnostic ignored "-Wstrict-overflow"
|
|
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
|
#endif
|
|
|
|
#define IMGUI_DEBUG_NAV_SCORING 0
|
|
#define IMGUI_DEBUG_NAV_RECTS 0
|
|
#define IMGUI_DEBUG_INI_SETTINGS 0
|
|
|
|
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f;
|
|
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f;
|
|
|
|
static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f;
|
|
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;
|
|
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f;
|
|
|
|
static void SetCurrentWindow(ImGuiWindow* window);
|
|
static void FindHoveredWindow();
|
|
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
|
|
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
|
|
|
|
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
|
|
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
|
|
|
|
static ImRect GetViewportRect();
|
|
|
|
static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
|
|
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
|
|
static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
|
|
static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
|
|
static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
|
|
static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
|
|
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
|
|
|
|
namespace ImGui
|
|
{
|
|
static void NavUpdate();
|
|
static void NavUpdateWindowing();
|
|
static void NavUpdateWindowingOverlay();
|
|
static void NavUpdateMoveResult();
|
|
static void NavUpdateInitResult();
|
|
static float NavUpdatePageUpPageDown();
|
|
static inline void NavUpdateAnyRequestFlag();
|
|
static void NavEndFrame();
|
|
static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
|
|
static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
|
|
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
|
|
static ImVec2 NavCalcPreferredRefPos();
|
|
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
|
|
static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
|
|
static int FindWindowFocusIndex(ImGuiWindow* window);
|
|
|
|
static void ErrorCheckNewFrameSanityChecks();
|
|
static void ErrorCheckEndFrameSanityChecks();
|
|
|
|
static void UpdateSettings();
|
|
static void UpdateMouseInputs();
|
|
static void UpdateMouseWheel();
|
|
static void UpdateTabFocus();
|
|
static void UpdateDebugToolItemPicker();
|
|
static 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);
|
|
static void RenderWindowOuterBorders(ImGuiWindow* window);
|
|
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
|
|
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
|
|
|
|
}
|
|
|
|
#ifndef GImGui
|
|
ImGuiContext* GImGui = NULL;
|
|
#endif
|
|
|
|
#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
|
|
static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
|
|
static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
|
|
#else
|
|
static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
|
|
static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
|
|
#endif
|
|
|
|
static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
|
|
static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
|
|
static void* GImAllocatorUserData = NULL;
|
|
|
|
ImGuiStyle::ImGuiStyle()
|
|
{
|
|
Alpha = 1.0f;
|
|
WindowPadding = ImVec2(8,8);
|
|
WindowRounding = 0.0f;
|
|
WindowBorderSize = 1.0f;
|
|
WindowMinSize = ImVec2(32,32);
|
|
WindowTitleAlign = ImVec2(0.0f,0.5f);
|
|
WindowMenuButtonPosition= ImGuiDir_Left;
|
|
ChildRounding = 0.0f;
|
|
ChildBorderSize = 1.0f;
|
|
PopupRounding = 0.0f;
|
|
PopupBorderSize = 1.0f;
|
|
FramePadding = ImVec2(4,3);
|
|
FrameRounding = 0.0f;
|
|
FrameBorderSize = 0.0f;
|
|
ItemSpacing = ImVec2(8,4);
|
|
ItemInnerSpacing = ImVec2(4,4);
|
|
CellPadding = ImVec2(4,2);
|
|
TouchExtraPadding = ImVec2(0,0);
|
|
IndentSpacing = 21.0f;
|
|
ColumnsMinSpacing = 6.0f;
|
|
ScrollbarSize = 14.0f;
|
|
ScrollbarRounding = 9.0f;
|
|
GrabMinSize = 10.0f;
|
|
GrabRounding = 0.0f;
|
|
LogSliderDeadzone = 4.0f;
|
|
TabRounding = 4.0f;
|
|
TabBorderSize = 0.0f;
|
|
TabMinWidthForCloseButton = 0.0f;
|
|
ColorButtonPosition = ImGuiDir_Right;
|
|
ButtonTextAlign = ImVec2(0.5f,0.5f);
|
|
SelectableTextAlign = ImVec2(0.0f,0.0f);
|
|
DisplayWindowPadding = ImVec2(19,19);
|
|
DisplaySafeAreaPadding = ImVec2(3,3);
|
|
MouseCursorScale = 1.0f;
|
|
AntiAliasedLines = true;
|
|
AntiAliasedLinesUseTex = true;
|
|
AntiAliasedFill = true;
|
|
CurveTessellationTol = 1.25f;
|
|
CircleSegmentMaxError = 1.60f;
|
|
|
|
ImGui::StyleColorsDark(this);
|
|
}
|
|
|
|
void ImGuiStyle::ScaleAllSizes(float scale_factor)
|
|
{
|
|
WindowPadding = ImFloor(WindowPadding * scale_factor);
|
|
WindowRounding = ImFloor(WindowRounding * scale_factor);
|
|
WindowMinSize = ImFloor(WindowMinSize * scale_factor);
|
|
ChildRounding = ImFloor(ChildRounding * scale_factor);
|
|
PopupRounding = ImFloor(PopupRounding * scale_factor);
|
|
FramePadding = ImFloor(FramePadding * scale_factor);
|
|
FrameRounding = ImFloor(FrameRounding * scale_factor);
|
|
ItemSpacing = ImFloor(ItemSpacing * scale_factor);
|
|
ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
|
|
CellPadding = ImFloor(CellPadding * scale_factor);
|
|
TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
|
|
IndentSpacing = ImFloor(IndentSpacing * scale_factor);
|
|
ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
|
|
ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
|
|
ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
|
|
GrabMinSize = ImFloor(GrabMinSize * scale_factor);
|
|
GrabRounding = ImFloor(GrabRounding * scale_factor);
|
|
LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
|
|
TabRounding = ImFloor(TabRounding * scale_factor);
|
|
TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
|
|
DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
|
|
DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
|
|
MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
|
|
}
|
|
|
|
ImGuiIO::ImGuiIO()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT);
|
|
|
|
ConfigFlags = ImGuiConfigFlags_None;
|
|
BackendFlags = ImGuiBackendFlags_None;
|
|
DisplaySize = ImVec2(-1.0f, -1.0f);
|
|
DeltaTime = 1.0f / 60.0f;
|
|
IniSavingRate = 5.0f;
|
|
IniFilename = "imgui.ini";
|
|
LogFilename = "imgui_log.txt";
|
|
MouseDoubleClickTime = 0.30f;
|
|
MouseDoubleClickMaxDist = 6.0f;
|
|
for (int i = 0; i < ImGuiKey_COUNT; i++)
|
|
KeyMap[i] = -1;
|
|
KeyRepeatDelay = 0.275f;
|
|
KeyRepeatRate = 0.050f;
|
|
UserData = NULL;
|
|
|
|
Fonts = NULL;
|
|
FontGlobalScale = 1.0f;
|
|
FontDefault = NULL;
|
|
FontAllowUserScaling = false;
|
|
DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
|
|
|
|
MouseDrawCursor = false;
|
|
#ifdef __APPLE__
|
|
ConfigMacOSXBehaviors = true;
|
|
#else
|
|
ConfigMacOSXBehaviors = false;
|
|
#endif
|
|
ConfigInputTextCursorBlink = true;
|
|
ConfigWindowsResizeFromEdges = true;
|
|
ConfigWindowsMoveFromTitleBarOnly = false;
|
|
ConfigMemoryCompactTimer = 60.0f;
|
|
|
|
BackendPlatformName = BackendRendererName = NULL;
|
|
BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
|
|
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;
|
|
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
|
|
ClipboardUserData = NULL;
|
|
ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
|
|
ImeWindowHandle = NULL;
|
|
|
|
MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
|
MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
|
|
MouseDragThreshold = 6.0f;
|
|
for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
|
|
for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
|
|
for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
|
|
}
|
|
|
|
void ImGuiIO::AddInputCharacter(unsigned int c)
|
|
{
|
|
if (c != 0)
|
|
InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
|
|
}
|
|
|
|
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
|
{
|
|
if (c == 0 && InputQueueSurrogate == 0)
|
|
return;
|
|
|
|
if ((c & 0xFC00) == 0xD800)
|
|
{
|
|
if (InputQueueSurrogate != 0)
|
|
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
|
InputQueueSurrogate = c;
|
|
return;
|
|
}
|
|
|
|
ImWchar cp = c;
|
|
if (InputQueueSurrogate != 0)
|
|
{
|
|
if ((c & 0xFC00) != 0xDC00)
|
|
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
|
else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF))
|
|
cp = IM_UNICODE_CODEPOINT_INVALID;
|
|
else
|
|
cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
|
|
InputQueueSurrogate = 0;
|
|
}
|
|
InputQueueCharacters.push_back(cp);
|
|
}
|
|
|
|
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
|
{
|
|
while (*utf8_chars != 0)
|
|
{
|
|
unsigned int c = 0;
|
|
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
|
|
if (c != 0)
|
|
InputQueueCharacters.push_back((ImWchar)c);
|
|
}
|
|
}
|
|
|
|
void ImGuiIO::ClearInputCharacters()
|
|
{
|
|
InputQueueCharacters.resize(0);
|
|
}
|
|
|
|
ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
|
|
{
|
|
IM_ASSERT(num_segments > 0);
|
|
ImVec2 p_last = p1;
|
|
ImVec2 p_closest;
|
|
float p_closest_dist2 = FLT_MAX;
|
|
float t_step = 1.0f / (float)num_segments;
|
|
for (int i_step = 1; i_step <= num_segments; i_step++)
|
|
{
|
|
ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
|
|
ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
|
|
float dist2 = ImLengthSqr(p - p_line);
|
|
if (dist2 < p_closest_dist2)
|
|
{
|
|
p_closest = p_line;
|
|
p_closest_dist2 = dist2;
|
|
}
|
|
p_last = p_current;
|
|
}
|
|
return p_closest;
|
|
}
|
|
|
|
static 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)
|
|
{
|
|
float dx = x4 - x1;
|
|
float dy = y4 - y1;
|
|
float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
|
|
float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
|
|
d2 = (d2 >= 0) ? d2 : -d2;
|
|
d3 = (d3 >= 0) ? d3 : -d3;
|
|
if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
|
|
{
|
|
ImVec2 p_current(x4, y4);
|
|
ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
|
|
float dist2 = ImLengthSqr(p - p_line);
|
|
if (dist2 < p_closest_dist2)
|
|
{
|
|
p_closest = p_line;
|
|
p_closest_dist2 = dist2;
|
|
}
|
|
p_last = p_current;
|
|
}
|
|
else if (level < 10)
|
|
{
|
|
float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
|
|
float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
|
|
float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
|
|
float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
|
|
float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
|
|
float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
|
|
ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
|
|
ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
|
|
}
|
|
}
|
|
|
|
ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
|
|
{
|
|
IM_ASSERT(tess_tol > 0.0f);
|
|
ImVec2 p_last = p1;
|
|
ImVec2 p_closest;
|
|
float p_closest_dist2 = FLT_MAX;
|
|
ImBezierCubicClosestPointCasteljauStep(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);
|
|
return p_closest;
|
|
}
|
|
|
|
ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
|
|
{
|
|
ImVec2 ap = p - a;
|
|
ImVec2 ab_dir = b - a;
|
|
float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
|
|
if (dot < 0.0f)
|
|
return a;
|
|
float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
|
|
if (dot > ab_len_sqr)
|
|
return b;
|
|
return a + ab_dir * dot / ab_len_sqr;
|
|
}
|
|
|
|
bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
|
|
{
|
|
bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
|
|
bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
|
|
bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
|
|
return ((b1 == b2) && (b2 == b3));
|
|
}
|
|
|
|
void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
|
|
{
|
|
ImVec2 v0 = b - a;
|
|
ImVec2 v1 = c - a;
|
|
ImVec2 v2 = p - a;
|
|
const float denom = v0.x * v1.y - v1.x * v0.y;
|
|
out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
|
|
out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
|
|
out_u = 1.0f - out_v - out_w;
|
|
}
|
|
|
|
ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
|
|
{
|
|
ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
|
|
ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
|
|
ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
|
|
float dist2_ab = ImLengthSqr(p - proj_ab);
|
|
float dist2_bc = ImLengthSqr(p - proj_bc);
|
|
float dist2_ca = ImLengthSqr(p - proj_ca);
|
|
float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
|
|
if (m == dist2_ab)
|
|
return proj_ab;
|
|
if (m == dist2_bc)
|
|
return proj_bc;
|
|
return proj_ca;
|
|
}
|
|
|
|
int ImStricmp(const char* str1, const char* str2)
|
|
{
|
|
int d;
|
|
while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
|
|
return d;
|
|
}
|
|
|
|
int ImStrnicmp(const char* str1, const char* str2, size_t count)
|
|
{
|
|
int d = 0;
|
|
while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
|
|
return d;
|
|
}
|
|
|
|
void ImStrncpy(char* dst, const char* src, size_t count)
|
|
{
|
|
if (count < 1)
|
|
return;
|
|
if (count > 1)
|
|
strncpy(dst, src, count - 1);
|
|
dst[count - 1] = 0;
|
|
}
|
|
|
|
char* ImStrdup(const char* str)
|
|
{
|
|
size_t len = strlen(str);
|
|
void* buf = IM_ALLOC(len + 1);
|
|
return (char*)memcpy(buf, (const void*)str, len + 1);
|
|
}
|
|
|
|
char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
|
|
{
|
|
size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
|
|
size_t src_size = strlen(src) + 1;
|
|
if (dst_buf_size < src_size)
|
|
{
|
|
IM_FREE(dst);
|
|
dst = (char*)IM_ALLOC(src_size);
|
|
if (p_dst_size)
|
|
*p_dst_size = src_size;
|
|
}
|
|
return (char*)memcpy(dst, (const void*)src, src_size);
|
|
}
|
|
|
|
const char* ImStrchrRange(const char* str, const char* str_end, char c)
|
|
{
|
|
const char* p = (const char*)memchr(str, (int)c, str_end - str);
|
|
return p;
|
|
}
|
|
|
|
int ImStrlenW(const ImWchar* str)
|
|
{
|
|
int n = 0;
|
|
while (*str++) n++;
|
|
return n;
|
|
}
|
|
|
|
const char* ImStreolRange(const char* str, const char* str_end)
|
|
{
|
|
const char* p = (const char*)memchr(str, '\n', str_end - str);
|
|
return p ? p : str_end;
|
|
}
|
|
|
|
const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin)
|
|
{
|
|
while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
|
|
buf_mid_line--;
|
|
return buf_mid_line;
|
|
}
|
|
|
|
const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
|
|
{
|
|
if (!needle_end)
|
|
needle_end = needle + strlen(needle);
|
|
|
|
const char un0 = (char)toupper(*needle);
|
|
while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
|
|
{
|
|
if (toupper(*haystack) == un0)
|
|
{
|
|
const char* b = needle + 1;
|
|
for (const char* a = haystack + 1; b < needle_end; a++, b++)
|
|
if (toupper(*a) != toupper(*b))
|
|
break;
|
|
if (b == needle_end)
|
|
return haystack;
|
|
}
|
|
haystack++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void ImStrTrimBlanks(char* buf)
|
|
{
|
|
char* p = buf;
|
|
while (p[0] == ' ' || p[0] == '\t')
|
|
p++;
|
|
char* p_start = p;
|
|
while (*p != 0)
|
|
p++;
|
|
while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))
|
|
p--;
|
|
if (p_start != buf)
|
|
memmove(buf, p_start, p - p_start);
|
|
buf[p - p_start] = 0;
|
|
}
|
|
|
|
const char* ImStrSkipBlank(const char* str)
|
|
{
|
|
while (str[0] == ' ' || str[0] == '\t')
|
|
str++;
|
|
return str;
|
|
}
|
|
|
|
#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
|
|
|
|
#ifdef IMGUI_USE_STB_SPRINTF
|
|
#define STB_SPRINTF_IMPLEMENTATION
|
|
#include "stb_sprintf.h"
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) && !defined(vsnprintf)
|
|
#define vsnprintf _vsnprintf
|
|
#endif
|
|
|
|
int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
#ifdef IMGUI_USE_STB_SPRINTF
|
|
int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
|
|
#else
|
|
int w = vsnprintf(buf, buf_size, fmt, args);
|
|
#endif
|
|
va_end(args);
|
|
if (buf == NULL)
|
|
return w;
|
|
if (w == -1 || w >= (int)buf_size)
|
|
w = (int)buf_size - 1;
|
|
buf[w] = 0;
|
|
return w;
|
|
}
|
|
|
|
int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
|
|
{
|
|
#ifdef IMGUI_USE_STB_SPRINTF
|
|
int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
|
|
#else
|
|
int w = vsnprintf(buf, buf_size, fmt, args);
|
|
#endif
|
|
if (buf == NULL)
|
|
return w;
|
|
if (w == -1 || w >= (int)buf_size)
|
|
w = (int)buf_size - 1;
|
|
buf[w] = 0;
|
|
return w;
|
|
}
|
|
#endif
|
|
|
|
static const ImU32 GCrc32LookupTable[256] =
|
|
{
|
|
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
|
|
0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
|
|
0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
|
|
0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
|
|
0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
|
|
0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
|
|
0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
|
|
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
|
|
0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
|
|
0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
|
|
0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
|
|
0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
|
|
0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
|
|
0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
|
|
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
|
|
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
|
|
};
|
|
|
|
ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed)
|
|
{
|
|
ImU32 crc = ~seed;
|
|
const unsigned char* data = (const unsigned char*)data_p;
|
|
const ImU32* crc32_lut = GCrc32LookupTable;
|
|
while (data_size-- != 0)
|
|
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
|
|
return ~crc;
|
|
}
|
|
|
|
ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
|
|
{
|
|
seed = ~seed;
|
|
ImU32 crc = seed;
|
|
const unsigned char* data = (const unsigned char*)data_p;
|
|
const ImU32* crc32_lut = GCrc32LookupTable;
|
|
if (data_size != 0)
|
|
{
|
|
while (data_size-- != 0)
|
|
{
|
|
unsigned char c = *data++;
|
|
if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
|
|
crc = seed;
|
|
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (unsigned char c = *data++)
|
|
{
|
|
if (c == '#' && data[0] == '#' && data[1] == '#')
|
|
crc = seed;
|
|
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
|
|
}
|
|
}
|
|
return ~crc;
|
|
}
|
|
|
|
#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
|
|
|
|
ImFileHandle ImFileOpen(const char* filename, const char* mode)
|
|
{
|
|
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
|
|
const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
|
|
const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
|
|
ImVector<ImWchar> buf;
|
|
buf.resize(filename_wsize + mode_wsize);
|
|
::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
|
|
::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
|
|
return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
|
|
#else
|
|
return fopen(filename, mode);
|
|
#endif
|
|
}
|
|
|
|
bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; }
|
|
ImU64 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; }
|
|
ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }
|
|
ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }
|
|
#endif
|
|
|
|
void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
|
|
{
|
|
IM_ASSERT(filename && mode);
|
|
if (out_file_size)
|
|
*out_file_size = 0;
|
|
|
|
ImFileHandle f;
|
|
if ((f = ImFileOpen(filename, mode)) == NULL)
|
|
return NULL;
|
|
|
|
size_t file_size = (size_t)ImFileGetSize(f);
|
|
if (file_size == (size_t)-1)
|
|
{
|
|
ImFileClose(f);
|
|
return NULL;
|
|
}
|
|
|
|
void* file_data = IM_ALLOC(file_size + padding_bytes);
|
|
if (file_data == NULL)
|
|
{
|
|
ImFileClose(f);
|
|
return NULL;
|
|
}
|
|
if (ImFileRead(file_data, 1, file_size, f) != file_size)
|
|
{
|
|
ImFileClose(f);
|
|
IM_FREE(file_data);
|
|
return NULL;
|
|
}
|
|
if (padding_bytes > 0)
|
|
memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
|
|
|
|
ImFileClose(f);
|
|
if (out_file_size)
|
|
*out_file_size = file_size;
|
|
|
|
return file_data;
|
|
}
|
|
|
|
int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
|
|
{
|
|
static 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 };
|
|
static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };
|
|
static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };
|
|
static const int shiftc[] = { 0, 18, 12, 6, 0 };
|
|
static const int shifte[] = { 0, 6, 4, 2, 0 };
|
|
int len = lengths[*(const unsigned char*)in_text >> 3];
|
|
int wanted = len + !len;
|
|
|
|
if (in_text_end == NULL)
|
|
in_text_end = in_text + wanted;
|
|
|
|
unsigned char s[4];
|
|
s[0] = in_text + 0 < in_text_end ? in_text[0] : 0;
|
|
s[1] = in_text + 1 < in_text_end ? in_text[1] : 0;
|
|
s[2] = in_text + 2 < in_text_end ? in_text[2] : 0;
|
|
s[3] = in_text + 3 < in_text_end ? in_text[3] : 0;
|
|
|
|
*out_char = (uint32_t)(s[0] & masks[len]) << 18;
|
|
*out_char |= (uint32_t)(s[1] & 0x3f) << 12;
|
|
*out_char |= (uint32_t)(s[2] & 0x3f) << 6;
|
|
*out_char |= (uint32_t)(s[3] & 0x3f) << 0;
|
|
*out_char >>= shiftc[len];
|
|
|
|
int e = 0;
|
|
e = (*out_char < mins[len]) << 6;
|
|
e |= ((*out_char >> 11) == 0x1b) << 7;
|
|
e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8;
|
|
e |= (s[1] & 0xc0) >> 2;
|
|
e |= (s[2] & 0xc0) >> 4;
|
|
e |= (s[3] ) >> 6;
|
|
e ^= 0x2a;
|
|
e >>= shifte[len];
|
|
|
|
if (e)
|
|
{
|
|
wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);
|
|
*out_char = IM_UNICODE_CODEPOINT_INVALID;
|
|
}
|
|
|
|
return wanted;
|
|
}
|
|
|
|
int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
|
|
{
|
|
ImWchar* buf_out = buf;
|
|
ImWchar* buf_end = buf + buf_size;
|
|
while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c;
|
|
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
|
|
if (c == 0)
|
|
break;
|
|
*buf_out++ = (ImWchar)c;
|
|
}
|
|
*buf_out = 0;
|
|
if (in_text_remaining)
|
|
*in_text_remaining = in_text;
|
|
return (int)(buf_out - buf);
|
|
}
|
|
|
|
int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
|
|
{
|
|
int char_count = 0;
|
|
while ((!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c;
|
|
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
|
|
if (c == 0)
|
|
break;
|
|
char_count++;
|
|
}
|
|
return char_count;
|
|
}
|
|
|
|
static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
|
|
{
|
|
if (c < 0x80)
|
|
{
|
|
buf[0] = (char)c;
|
|
return 1;
|
|
}
|
|
if (c < 0x800)
|
|
{
|
|
if (buf_size < 2) return 0;
|
|
buf[0] = (char)(0xc0 + (c >> 6));
|
|
buf[1] = (char)(0x80 + (c & 0x3f));
|
|
return 2;
|
|
}
|
|
if (c < 0x10000)
|
|
{
|
|
if (buf_size < 3) return 0;
|
|
buf[0] = (char)(0xe0 + (c >> 12));
|
|
buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
|
|
buf[2] = (char)(0x80 + ((c ) & 0x3f));
|
|
return 3;
|
|
}
|
|
if (c <= 0x10FFFF)
|
|
{
|
|
if (buf_size < 4) return 0;
|
|
buf[0] = (char)(0xf0 + (c >> 18));
|
|
buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
|
|
buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
|
|
buf[3] = (char)(0x80 + ((c ) & 0x3f));
|
|
return 4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
|
|
{
|
|
unsigned int unused = 0;
|
|
return ImTextCharFromUtf8(&unused, in_text, in_text_end);
|
|
}
|
|
|
|
static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
|
|
{
|
|
if (c < 0x80) return 1;
|
|
if (c < 0x800) return 2;
|
|
if (c < 0x10000) return 3;
|
|
if (c <= 0x10FFFF) return 4;
|
|
return 3;
|
|
}
|
|
|
|
int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
|
|
{
|
|
char* buf_out = buf;
|
|
const char* buf_end = buf + buf_size;
|
|
while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c = (unsigned int)(*in_text++);
|
|
if (c < 0x80)
|
|
*buf_out++ = (char)c;
|
|
else
|
|
buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
|
|
}
|
|
*buf_out = 0;
|
|
return (int)(buf_out - buf);
|
|
}
|
|
|
|
int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
|
|
{
|
|
int bytes_count = 0;
|
|
while ((!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c = (unsigned int)(*in_text++);
|
|
if (c < 0x80)
|
|
bytes_count++;
|
|
else
|
|
bytes_count += ImTextCountUtf8BytesFromChar(c);
|
|
}
|
|
return bytes_count;
|
|
}
|
|
|
|
IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
|
|
{
|
|
float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
|
|
int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
|
|
int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
|
|
int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
|
|
return IM_COL32(r, g, b, 0xFF);
|
|
}
|
|
|
|
ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
|
|
{
|
|
float s = 1.0f / 255.0f;
|
|
return ImVec4(
|
|
((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
|
|
((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
|
|
((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
|
|
((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
|
|
}
|
|
|
|
ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
|
|
{
|
|
ImU32 out;
|
|
out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
|
|
return out;
|
|
}
|
|
|
|
void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
|
|
{
|
|
float K = 0.f;
|
|
if (g < b)
|
|
{
|
|
ImSwap(g, b);
|
|
K = -1.f;
|
|
}
|
|
if (r < g)
|
|
{
|
|
ImSwap(r, g);
|
|
K = -2.f / 6.f - K;
|
|
}
|
|
|
|
const float chroma = r - (g < b ? g : b);
|
|
out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
|
|
out_s = chroma / (r + 1e-20f);
|
|
out_v = r;
|
|
}
|
|
|
|
void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
|
|
{
|
|
if (s == 0.0f)
|
|
{
|
|
out_r = out_g = out_b = v;
|
|
return;
|
|
}
|
|
|
|
h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
|
|
int i = (int)h;
|
|
float f = h - (float)i;
|
|
float p = v * (1.0f - s);
|
|
float q = v * (1.0f - s * f);
|
|
float t = v * (1.0f - s * (1.0f - f));
|
|
|
|
switch (i)
|
|
{
|
|
case 0: out_r = v; out_g = t; out_b = p; break;
|
|
case 1: out_r = q; out_g = v; out_b = p; break;
|
|
case 2: out_r = p; out_g = v; out_b = t; break;
|
|
case 3: out_r = p; out_g = q; out_b = v; break;
|
|
case 4: out_r = t; out_g = p; out_b = v; break;
|
|
case 5: default: out_r = v; out_g = p; out_b = q; break;
|
|
}
|
|
}
|
|
|
|
static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
|
|
{
|
|
ImGuiStorage::ImGuiStoragePair* first = data.Data;
|
|
ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
|
|
size_t count = (size_t)(last - first);
|
|
while (count > 0)
|
|
{
|
|
size_t count2 = count >> 1;
|
|
ImGuiStorage::ImGuiStoragePair* mid = first + count2;
|
|
if (mid->key < key)
|
|
{
|
|
first = ++mid;
|
|
count -= count2 + 1;
|
|
}
|
|
else
|
|
{
|
|
count = count2;
|
|
}
|
|
}
|
|
return first;
|
|
}
|
|
|
|
void ImGuiStorage::BuildSortByKey()
|
|
{
|
|
struct StaticFunc
|
|
{
|
|
static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
|
|
{
|
|
if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
|
|
if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
|
|
return 0;
|
|
}
|
|
};
|
|
if (Data.Size > 1)
|
|
ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
|
|
}
|
|
|
|
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
|
|
if (it == Data.end() || it->key != key)
|
|
return default_val;
|
|
return it->val_i;
|
|
}
|
|
|
|
bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
|
|
{
|
|
return GetInt(key, default_val ? 1 : 0) != 0;
|
|
}
|
|
|
|
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
|
|
if (it == Data.end() || it->key != key)
|
|
return default_val;
|
|
return it->val_f;
|
|
}
|
|
|
|
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
|
|
if (it == Data.end() || it->key != key)
|
|
return NULL;
|
|
return it->val_p;
|
|
}
|
|
|
|
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
it = Data.insert(it, ImGuiStoragePair(key, default_val));
|
|
return &it->val_i;
|
|
}
|
|
|
|
bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
|
|
{
|
|
return (bool*)GetIntRef(key, default_val ? 1 : 0);
|
|
}
|
|
|
|
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
it = Data.insert(it, ImGuiStoragePair(key, default_val));
|
|
return &it->val_f;
|
|
}
|
|
|
|
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
it = Data.insert(it, ImGuiStoragePair(key, default_val));
|
|
return &it->val_p;
|
|
}
|
|
|
|
void ImGuiStorage::SetInt(ImGuiID key, int val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
{
|
|
Data.insert(it, ImGuiStoragePair(key, val));
|
|
return;
|
|
}
|
|
it->val_i = val;
|
|
}
|
|
|
|
void ImGuiStorage::SetBool(ImGuiID key, bool val)
|
|
{
|
|
SetInt(key, val ? 1 : 0);
|
|
}
|
|
|
|
void ImGuiStorage::SetFloat(ImGuiID key, float val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
{
|
|
Data.insert(it, ImGuiStoragePair(key, val));
|
|
return;
|
|
}
|
|
it->val_f = val;
|
|
}
|
|
|
|
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
|
|
{
|
|
ImGuiStoragePair* it = LowerBound(Data, key);
|
|
if (it == Data.end() || it->key != key)
|
|
{
|
|
Data.insert(it, ImGuiStoragePair(key, val));
|
|
return;
|
|
}
|
|
it->val_p = val;
|
|
}
|
|
|
|
void ImGuiStorage::SetAllInt(int v)
|
|
{
|
|
for (int i = 0; i < Data.Size; i++)
|
|
Data[i].val_i = v;
|
|
}
|
|
|
|
ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
|
|
{
|
|
if (default_filter)
|
|
{
|
|
ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
|
|
Build();
|
|
}
|
|
else
|
|
{
|
|
InputBuf[0] = 0;
|
|
CountGrep = 0;
|
|
}
|
|
}
|
|
|
|
bool ImGuiTextFilter::Draw(const char* label, float width)
|
|
{
|
|
if (width != 0.0f)
|
|
ImGui::SetNextItemWidth(width);
|
|
bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
|
|
if (value_changed)
|
|
Build();
|
|
return value_changed;
|
|
}
|
|
|
|
void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
|
|
{
|
|
out->resize(0);
|
|
const char* wb = b;
|
|
const char* we = wb;
|
|
while (we < e)
|
|
{
|
|
if (*we == separator)
|
|
{
|
|
out->push_back(ImGuiTextRange(wb, we));
|
|
wb = we + 1;
|
|
}
|
|
we++;
|
|
}
|
|
if (wb != we)
|
|
out->push_back(ImGuiTextRange(wb, we));
|
|
}
|
|
|
|
void ImGuiTextFilter::Build()
|
|
{
|
|
Filters.resize(0);
|
|
ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
|
|
input_range.split(',', &Filters);
|
|
|
|
CountGrep = 0;
|
|
for (int i = 0; i != Filters.Size; i++)
|
|
{
|
|
ImGuiTextRange& f = Filters[i];
|
|
while (f.b < f.e && ImCharIsBlankA(f.b[0]))
|
|
f.b++;
|
|
while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
|
|
f.e--;
|
|
if (f.empty())
|
|
continue;
|
|
if (Filters[i].b[0] != '-')
|
|
CountGrep += 1;
|
|
}
|
|
}
|
|
|
|
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
|
|
{
|
|
if (Filters.empty())
|
|
return true;
|
|
|
|
if (text == NULL)
|
|
text = "";
|
|
|
|
for (int i = 0; i != Filters.Size; i++)
|
|
{
|
|
const ImGuiTextRange& f = Filters[i];
|
|
if (f.empty())
|
|
continue;
|
|
if (f.b[0] == '-')
|
|
{
|
|
if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (ImStristr(text, text_end, f.b, f.e) != NULL)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (CountGrep == 0)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifndef va_copy
|
|
#if defined(__GNUC__) || defined(__clang__)
|
|
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
|
#else
|
|
#define va_copy(dest, src) (dest = src)
|
|
#endif
|
|
#endif
|
|
|
|
char ImGuiTextBuffer::EmptyString[1] = { 0 };
|
|
|
|
void ImGuiTextBuffer::append(const char* str, const char* str_end)
|
|
{
|
|
int len = str_end ? (int)(str_end - str) : (int)strlen(str);
|
|
|
|
const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
|
|
const int needed_sz = write_off + len;
|
|
if (write_off + len >= Buf.Capacity)
|
|
{
|
|
int new_capacity = Buf.Capacity * 2;
|
|
Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
|
|
}
|
|
|
|
Buf.resize(needed_sz);
|
|
memcpy(&Buf[write_off - 1], str, (size_t)len);
|
|
Buf[write_off - 1 + len] = 0;
|
|
}
|
|
|
|
void ImGuiTextBuffer::appendf(const char* fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
appendfv(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
|
|
{
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
|
|
int len = ImFormatStringV(NULL, 0, fmt, args);
|
|
if (len <= 0)
|
|
{
|
|
va_end(args_copy);
|
|
return;
|
|
}
|
|
|
|
const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
|
|
const int needed_sz = write_off + len;
|
|
if (write_off + len >= Buf.Capacity)
|
|
{
|
|
int new_capacity = Buf.Capacity * 2;
|
|
Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
|
|
}
|
|
|
|
Buf.resize(needed_sz);
|
|
ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
|
|
va_end(args_copy);
|
|
}
|
|
|
|
static bool GetSkipItemForListClipping()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
|
|
}
|
|
|
|
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (g.LogEnabled)
|
|
{
|
|
*out_items_display_start = 0;
|
|
*out_items_display_end = items_count;
|
|
return;
|
|
}
|
|
if (GetSkipItemForListClipping())
|
|
{
|
|
*out_items_display_start = *out_items_display_end = 0;
|
|
return;
|
|
}
|
|
|
|
ImRect unclipped_rect = window->ClipRect;
|
|
if (g.NavMoveRequest)
|
|
unclipped_rect.Add(g.NavScoringRect);
|
|
if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
|
|
unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
|
|
|
|
const ImVec2 pos = window->DC.CursorPos;
|
|
int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
|
|
int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
|
|
|
|
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
|
|
start--;
|
|
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
|
|
end++;
|
|
|
|
start = ImClamp(start, 0, items_count);
|
|
end = ImClamp(end + 1, start, items_count);
|
|
*out_items_display_start = start;
|
|
*out_items_display_end = end;
|
|
}
|
|
|
|
static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
float off_y = pos_y - window->DC.CursorPos.y;
|
|
window->DC.CursorPos.y = pos_y;
|
|
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;
|
|
window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y);
|
|
if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
|
|
columns->LineMinY = window->DC.CursorPos.y;
|
|
if (ImGuiTable* table = g.CurrentTable)
|
|
{
|
|
if (table->IsInsideRow)
|
|
ImGui::TableEndRow(table);
|
|
table->RowPosY2 = window->DC.CursorPos.y;
|
|
const int row_increase = (int)((off_y / line_height) + 0.5f);
|
|
table->RowBgColorCounter += row_increase;
|
|
}
|
|
}
|
|
|
|
ImGuiListClipper::ImGuiListClipper()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
ItemsCount = -1;
|
|
}
|
|
|
|
ImGuiListClipper::~ImGuiListClipper()
|
|
{
|
|
IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?");
|
|
}
|
|
|
|
void ImGuiListClipper::Begin(int items_count, float items_height)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
if (ImGuiTable* table = g.CurrentTable)
|
|
if (table->IsInsideRow)
|
|
ImGui::TableEndRow(table);
|
|
|
|
StartPosY = window->DC.CursorPos.y;
|
|
ItemsHeight = items_height;
|
|
ItemsCount = items_count;
|
|
ItemsFrozen = 0;
|
|
StepNo = 0;
|
|
DisplayStart = -1;
|
|
DisplayEnd = 0;
|
|
}
|
|
|
|
void ImGuiListClipper::End()
|
|
{
|
|
if (ItemsCount < 0)
|
|
return;
|
|
|
|
if (ItemsCount < INT_MAX && DisplayStart >= 0)
|
|
SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight);
|
|
ItemsCount = -1;
|
|
StepNo = 3;
|
|
}
|
|
|
|
bool ImGuiListClipper::Step()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
ImGuiTable* table = g.CurrentTable;
|
|
if (table && table->IsInsideRow)
|
|
ImGui::TableEndRow(table);
|
|
|
|
if (ItemsCount == 0 || GetSkipItemForListClipping())
|
|
{
|
|
End();
|
|
return false;
|
|
}
|
|
|
|
if (StepNo == 0)
|
|
{
|
|
if (table != NULL && !table->IsUnfrozenRows)
|
|
{
|
|
DisplayStart = ItemsFrozen;
|
|
DisplayEnd = ItemsFrozen + 1;
|
|
ItemsFrozen++;
|
|
return true;
|
|
}
|
|
|
|
StartPosY = window->DC.CursorPos.y;
|
|
if (ItemsHeight <= 0.0f)
|
|
{
|
|
DisplayStart = ItemsFrozen;
|
|
DisplayEnd = ItemsFrozen + 1;
|
|
StepNo = 1;
|
|
return true;
|
|
}
|
|
|
|
DisplayStart = DisplayEnd;
|
|
StepNo = 2;
|
|
}
|
|
|
|
if (StepNo == 1)
|
|
{
|
|
IM_ASSERT(ItemsHeight <= 0.0f);
|
|
if (table)
|
|
{
|
|
const float pos_y1 = table->RowPosY1;
|
|
const float pos_y2 = table->RowPosY2;
|
|
ItemsHeight = pos_y2 - pos_y1;
|
|
window->DC.CursorPos.y = pos_y2;
|
|
}
|
|
else
|
|
{
|
|
ItemsHeight = window->DC.CursorPos.y - StartPosY;
|
|
}
|
|
IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
|
|
StepNo = 2;
|
|
}
|
|
|
|
if (DisplayEnd >= ItemsCount)
|
|
{
|
|
End();
|
|
return false;
|
|
}
|
|
|
|
if (StepNo == 2)
|
|
{
|
|
IM_ASSERT(ItemsHeight > 0.0f);
|
|
|
|
int already_submitted = DisplayEnd;
|
|
ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd);
|
|
DisplayStart += already_submitted;
|
|
DisplayEnd += already_submitted;
|
|
|
|
if (DisplayStart > already_submitted)
|
|
SetCursorPosYAndSetupForPrevLine(StartPosY + (DisplayStart - ItemsFrozen) * ItemsHeight, ItemsHeight);
|
|
|
|
StepNo = 3;
|
|
return true;
|
|
}
|
|
|
|
if (StepNo == 3)
|
|
{
|
|
if (ItemsCount < INT_MAX)
|
|
SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight);
|
|
ItemsCount = -1;
|
|
return false;
|
|
}
|
|
|
|
IM_ASSERT(0);
|
|
return false;
|
|
}
|
|
|
|
ImGuiStyle& ImGui::GetStyle()
|
|
{
|
|
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
|
|
return GImGui->Style;
|
|
}
|
|
|
|
ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
|
|
{
|
|
ImGuiStyle& style = GImGui->Style;
|
|
ImVec4 c = style.Colors[idx];
|
|
c.w *= style.Alpha * alpha_mul;
|
|
return ColorConvertFloat4ToU32(c);
|
|
}
|
|
|
|
ImU32 ImGui::GetColorU32(const ImVec4& col)
|
|
{
|
|
ImGuiStyle& style = GImGui->Style;
|
|
ImVec4 c = col;
|
|
c.w *= style.Alpha;
|
|
return ColorConvertFloat4ToU32(c);
|
|
}
|
|
|
|
const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
|
|
{
|
|
ImGuiStyle& style = GImGui->Style;
|
|
return style.Colors[idx];
|
|
}
|
|
|
|
ImU32 ImGui::GetColorU32(ImU32 col)
|
|
{
|
|
ImGuiStyle& style = GImGui->Style;
|
|
if (style.Alpha >= 1.0f)
|
|
return col;
|
|
ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
|
|
a = (ImU32)(a * style.Alpha);
|
|
return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
|
|
}
|
|
|
|
void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiColorMod backup;
|
|
backup.Col = idx;
|
|
backup.BackupValue = g.Style.Colors[idx];
|
|
g.ColorStack.push_back(backup);
|
|
g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
|
|
}
|
|
|
|
void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiColorMod backup;
|
|
backup.Col = idx;
|
|
backup.BackupValue = g.Style.Colors[idx];
|
|
g.ColorStack.push_back(backup);
|
|
g.Style.Colors[idx] = col;
|
|
}
|
|
|
|
void ImGui::PopStyleColor(int count)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
while (count > 0)
|
|
{
|
|
ImGuiColorMod& backup = g.ColorStack.back();
|
|
g.Style.Colors[backup.Col] = backup.BackupValue;
|
|
g.ColorStack.pop_back();
|
|
count--;
|
|
}
|
|
}
|
|
|
|
struct ImGuiStyleVarInfo
|
|
{
|
|
ImGuiDataType Type;
|
|
ImU32 Count;
|
|
ImU32 Offset;
|
|
void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
|
|
};
|
|
|
|
static const ImGuiStyleVarInfo GStyleVarInfo[] =
|
|
{
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },
|
|
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },
|
|
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) },
|
|
};
|
|
|
|
static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
|
|
{
|
|
IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
|
|
IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
|
|
return &GStyleVarInfo[idx];
|
|
}
|
|
|
|
void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
|
|
{
|
|
const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
|
|
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
float* pvar = (float*)var_info->GetVarPtr(&g.Style);
|
|
g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
|
|
*pvar = val;
|
|
return;
|
|
}
|
|
IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
|
|
}
|
|
|
|
void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
|
|
{
|
|
const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
|
|
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
|
|
g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
|
|
*pvar = val;
|
|
return;
|
|
}
|
|
IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
|
|
}
|
|
|
|
void ImGui::PopStyleVar(int count)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
while (count > 0)
|
|
{
|
|
ImGuiStyleMod& backup = g.StyleVarStack.back();
|
|
const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
|
|
void* data = info->GetVarPtr(&g.Style);
|
|
if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
|
|
else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
|
|
g.StyleVarStack.pop_back();
|
|
count--;
|
|
}
|
|
}
|
|
|
|
const char* ImGui::GetStyleColorName(ImGuiCol idx)
|
|
{
|
|
switch (idx)
|
|
{
|
|
case ImGuiCol_Text: return "Text";
|
|
case ImGuiCol_TextDisabled: return "TextDisabled";
|
|
case ImGuiCol_WindowBg: return "WindowBg";
|
|
case ImGuiCol_ChildBg: return "ChildBg";
|
|
case ImGuiCol_PopupBg: return "PopupBg";
|
|
case ImGuiCol_Border: return "Border";
|
|
case ImGuiCol_BorderShadow: return "BorderShadow";
|
|
case ImGuiCol_FrameBg: return "FrameBg";
|
|
case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
|
|
case ImGuiCol_FrameBgActive: return "FrameBgActive";
|
|
case ImGuiCol_TitleBg: return "TitleBg";
|
|
case ImGuiCol_TitleBgActive: return "TitleBgActive";
|
|
case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
|
|
case ImGuiCol_MenuBarBg: return "MenuBarBg";
|
|
case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
|
|
case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
|
|
case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
|
|
case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
|
|
case ImGuiCol_CheckMark: return "CheckMark";
|
|
case ImGuiCol_SliderGrab: return "SliderGrab";
|
|
case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
|
|
case ImGuiCol_Button: return "Button";
|
|
case ImGuiCol_ButtonHovered: return "ButtonHovered";
|
|
case ImGuiCol_ButtonActive: return "ButtonActive";
|
|
case ImGuiCol_Header: return "Header";
|
|
case ImGuiCol_HeaderHovered: return "HeaderHovered";
|
|
case ImGuiCol_HeaderActive: return "HeaderActive";
|
|
case ImGuiCol_Separator: return "Separator";
|
|
case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
|
|
case ImGuiCol_SeparatorActive: return "SeparatorActive";
|
|
case ImGuiCol_ResizeGrip: return "ResizeGrip";
|
|
case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
|
|
case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
|
|
case ImGuiCol_Tab: return "Tab";
|
|
case ImGuiCol_TabHovered: return "TabHovered";
|
|
case ImGuiCol_TabActive: return "TabActive";
|
|
case ImGuiCol_TabUnfocused: return "TabUnfocused";
|
|
case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
|
|
case ImGuiCol_PlotLines: return "PlotLines";
|
|
case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
|
|
case ImGuiCol_PlotHistogram: return "PlotHistogram";
|
|
case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
|
|
case ImGuiCol_TableHeaderBg: return "TableHeaderBg";
|
|
case ImGuiCol_TableBorderStrong: return "TableBorderStrong";
|
|
case ImGuiCol_TableBorderLight: return "TableBorderLight";
|
|
case ImGuiCol_TableRowBg: return "TableRowBg";
|
|
case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
|
|
case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
|
|
case ImGuiCol_DragDropTarget: return "DragDropTarget";
|
|
case ImGuiCol_NavHighlight: return "NavHighlight";
|
|
case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
|
|
case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
|
|
case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
|
|
}
|
|
IM_ASSERT(0);
|
|
return "Unknown";
|
|
}
|
|
|
|
|
|
const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
|
|
{
|
|
const char* text_display_end = text;
|
|
if (!text_end)
|
|
text_end = (const char*)-1;
|
|
|
|
while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
|
|
text_display_end++;
|
|
return text_display_end;
|
|
}
|
|
|
|
void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash, ImU32 customcol)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
const char* text_display_end;
|
|
if (hide_text_after_hash)
|
|
{
|
|
text_display_end = FindRenderedTextEnd(text, text_end);
|
|
}
|
|
else
|
|
{
|
|
if (!text_end)
|
|
text_end = text + strlen(text);
|
|
text_display_end = text_end;
|
|
}
|
|
|
|
if (text != text_display_end)
|
|
{
|
|
if (!customcol)
|
|
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
|
|
else
|
|
window->DrawList->AddText(g.Font, g.FontSize, pos, customcol, text, text_display_end);
|
|
|
|
if (g.LogEnabled)
|
|
LogRenderedText(&pos, text, text_display_end);
|
|
}
|
|
}
|
|
|
|
void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
if (!text_end)
|
|
text_end = text + strlen(text);
|
|
|
|
if (text != text_end)
|
|
{
|
|
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
|
|
if (g.LogEnabled)
|
|
LogRenderedText(&pos, text, text_end);
|
|
}
|
|
}
|
|
|
|
void 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, ImU32 customcol)
|
|
{
|
|
ImVec2 pos = pos_min;
|
|
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
|
|
|
|
const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
|
|
const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
|
|
bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
|
|
if (clip_rect)
|
|
need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
|
|
|
|
if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
|
|
if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
|
|
|
|
if (need_clipping)
|
|
{
|
|
ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
|
|
|
|
if (!customcol)
|
|
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
|
|
else
|
|
draw_list->AddText(NULL, 0.0f, pos, customcol, text, text_display_end, 0.0f, &fine_clip_rect);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (!customcol)
|
|
draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
|
|
else
|
|
draw_list->AddText(NULL, 0.0f, pos, customcol, text, text_display_end, 0.0f, NULL);
|
|
}
|
|
}
|
|
|
|
void 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)
|
|
{
|
|
const char* text_display_end = FindRenderedTextEnd(text, text_end);
|
|
const int text_len = (int)(text_display_end - text);
|
|
if (text_len == 0)
|
|
return;
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
|
|
if (g.LogEnabled)
|
|
LogRenderedText(&pos_min, text, text_display_end);
|
|
}
|
|
|
|
|
|
void 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, ImColor customcolor)
|
|
{
|
|
const char* text_display_end = FindRenderedTextEnd(text, text_end);
|
|
const int text_len = (int)(text_display_end - text);
|
|
if (text_len == 0)
|
|
return;
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect, customcolor);
|
|
if (g.LogEnabled)
|
|
LogRenderedText(&pos_min, text, text_display_end);
|
|
}
|
|
|
|
|
|
void 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, ImU32 customcol)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (text_end_full == NULL)
|
|
text_end_full = FindRenderedTextEnd(text);
|
|
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
|
|
|
|
if (text_size.x > pos_max.x - pos_min.x)
|
|
{
|
|
const ImFont* font = draw_list->_Data->Font;
|
|
const float font_size = draw_list->_Data->FontSize;
|
|
const char* text_end_ellipsis = NULL;
|
|
|
|
ImWchar ellipsis_char = font->EllipsisChar;
|
|
int ellipsis_char_count = 1;
|
|
if (ellipsis_char == (ImWchar)-1)
|
|
{
|
|
ellipsis_char = (ImWchar)'.';
|
|
ellipsis_char_count = 3;
|
|
}
|
|
const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
|
|
|
|
float ellipsis_glyph_width = glyph->X1;
|
|
float ellipsis_total_width = ellipsis_glyph_width;
|
|
|
|
if (ellipsis_char_count > 1)
|
|
{
|
|
const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
|
|
ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
|
|
ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
|
|
}
|
|
|
|
const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
|
|
float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
|
|
if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
|
|
{
|
|
text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
|
|
text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
|
|
}
|
|
while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
|
|
{
|
|
text_end_ellipsis--;
|
|
text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x;
|
|
}
|
|
|
|
RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
|
|
float ellipsis_x = pos_min.x + text_size_clipped_x;
|
|
if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
|
|
for (int i = 0; i < ellipsis_char_count; i++)
|
|
{
|
|
if (!customcol)
|
|
font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
|
|
else
|
|
font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), customcol, ellipsis_char);
|
|
|
|
ellipsis_x += ellipsis_glyph_width;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f), 0, customcol);
|
|
}
|
|
|
|
if (g.LogEnabled)
|
|
LogRenderedText(&pos_min, text, text_end_full);
|
|
}
|
|
|
|
void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
|
|
const float border_size = g.Style.FrameBorderSize;
|
|
if (border && border_size > 0.0f)
|
|
{
|
|
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
|
|
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
|
|
}
|
|
}
|
|
|
|
void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
const float border_size = g.Style.FrameBorderSize;
|
|
if (border_size > 0.0f)
|
|
{
|
|
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
|
|
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
|
|
}
|
|
}
|
|
|
|
void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (id != g.NavId)
|
|
return;
|
|
if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
|
|
return;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (window->DC.NavHideHighlightOneFrame)
|
|
return;
|
|
|
|
float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
|
|
ImRect display_rect = bb;
|
|
display_rect.ClipWith(window->ClipRect);
|
|
if (flags & ImGuiNavHighlightFlags_TypeDefault)
|
|
{
|
|
const float THICKNESS = 2.0f;
|
|
const float DISTANCE = 3.0f + THICKNESS * 0.5f;
|
|
display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
|
|
bool fully_visible = window->ClipRect.Contains(display_rect);
|
|
if (!fully_visible)
|
|
window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
|
|
window->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, ImDrawCornerFlags_All, THICKNESS);
|
|
if (!fully_visible)
|
|
window->DrawList->PopClipRect();
|
|
}
|
|
if (flags & ImGuiNavHighlightFlags_TypeThin)
|
|
{
|
|
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
|
|
}
|
|
}
|
|
|
|
ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL)
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
Name = ImStrdup(name);
|
|
NameBufLen = (int)strlen(name) + 1;
|
|
ID = ImHashStr(name);
|
|
IDStack.push_back(ID);
|
|
MoveId = GetID("#MOVE");
|
|
ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
|
|
ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
|
|
AutoFitFramesX = AutoFitFramesY = -1;
|
|
AutoPosLastDirection = ImGuiDir_None;
|
|
SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
|
|
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
|
|
LastFrameActive = -1;
|
|
LastTimeActive = -1.0f;
|
|
FontWindowScale = 1.0f;
|
|
SettingsOffset = -1;
|
|
DrawList = &DrawListInst;
|
|
DrawList->_Data = &context->DrawListSharedData;
|
|
DrawList->_OwnerName = Name;
|
|
}
|
|
|
|
ImGuiWindow::~ImGuiWindow()
|
|
{
|
|
IM_ASSERT(DrawList == &DrawListInst);
|
|
IM_DELETE(Name);
|
|
for (int i = 0; i != ColumnsStorage.Size; i++)
|
|
ColumnsStorage[i].~ImGuiOldColumns();
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
|
ImGui::KeepAliveID(id);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetID(const void* ptr)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
|
ImGui::KeepAliveID(id);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetID(int n)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
|
ImGui::KeepAliveID(id);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
|
|
{
|
|
ImGuiID seed = IDStack.back();
|
|
const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
|
|
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
|
|
ImGui::KeepAliveID(id);
|
|
return id;
|
|
}
|
|
|
|
static void SetCurrentWindow(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.CurrentWindow = window;
|
|
g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
|
|
if (window)
|
|
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
|
|
}
|
|
|
|
void ImGui::GcCompactTransientMiscBuffers()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.ItemFlagsStack.clear();
|
|
g.GroupStack.clear();
|
|
TableGcCompactSettings();
|
|
}
|
|
|
|
void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
|
|
{
|
|
window->MemoryCompacted = true;
|
|
window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
|
|
window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
|
|
window->IDStack.clear();
|
|
window->DrawList->_ClearFreeMemory();
|
|
window->DC.ChildWindows.clear();
|
|
window->DC.ItemWidthStack.clear();
|
|
window->DC.TextWrapPosStack.clear();
|
|
}
|
|
|
|
void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
|
|
{
|
|
window->MemoryCompacted = false;
|
|
window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
|
|
window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
|
|
window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
|
|
}
|
|
|
|
void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.ActiveIdIsJustActivated = (g.ActiveId != id);
|
|
if (g.ActiveIdIsJustActivated)
|
|
{
|
|
g.ActiveIdTimer = 0.0f;
|
|
g.ActiveIdHasBeenPressedBefore = false;
|
|
g.ActiveIdHasBeenEditedBefore = false;
|
|
if (id != 0)
|
|
{
|
|
g.LastActiveId = id;
|
|
g.LastActiveIdTimer = 0.0f;
|
|
}
|
|
}
|
|
g.ActiveId = id;
|
|
g.ActiveIdAllowOverlap = false;
|
|
g.ActiveIdNoClearOnFocusLoss = false;
|
|
g.ActiveIdWindow = window;
|
|
g.ActiveIdHasBeenEditedThisFrame = false;
|
|
if (id)
|
|
{
|
|
g.ActiveIdIsAlive = id;
|
|
g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
|
}
|
|
|
|
g.ActiveIdUsingMouseWheel = false;
|
|
g.ActiveIdUsingNavDirMask = 0x00;
|
|
g.ActiveIdUsingNavInputMask = 0x00;
|
|
g.ActiveIdUsingKeyInputMask = 0x00;
|
|
}
|
|
|
|
void ImGui::ClearActiveID()
|
|
{
|
|
SetActiveID(0, NULL);
|
|
}
|
|
|
|
void ImGui::SetHoveredID(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.HoveredId = id;
|
|
g.HoveredIdAllowOverlap = false;
|
|
g.HoveredIdUsingMouseWheel = false;
|
|
if (id != 0 && g.HoveredIdPreviousFrame != id)
|
|
g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
|
|
}
|
|
|
|
ImGuiID ImGui::GetHoveredID()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
|
|
}
|
|
|
|
void ImGui::KeepAliveID(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.ActiveId == id)
|
|
g.ActiveIdIsAlive = id;
|
|
if (g.ActiveIdPreviousFrame == id)
|
|
g.ActiveIdPreviousFrameIsAlive = true;
|
|
}
|
|
|
|
void ImGui::MarkItemEdited(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
|
|
IM_UNUSED(id);
|
|
g.ActiveIdHasBeenEditedThisFrame = true;
|
|
g.ActiveIdHasBeenEditedBefore = true;
|
|
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
|
|
}
|
|
|
|
static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.NavWindow)
|
|
if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
|
|
if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
|
|
{
|
|
if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
|
|
return false;
|
|
if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (g.NavDisableMouseHover && !g.NavDisableHighlight)
|
|
return IsItemFocused();
|
|
|
|
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
|
|
return false;
|
|
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);
|
|
|
|
if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
|
|
return false;
|
|
|
|
if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
|
|
if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
|
|
return false;
|
|
|
|
if (!IsWindowContentHoverable(window, flags))
|
|
return false;
|
|
|
|
if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
|
|
return false;
|
|
|
|
if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
|
|
return false;
|
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (g.HoveredWindow != window)
|
|
return false;
|
|
if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
|
|
return false;
|
|
if (!IsMouseHoveringRect(bb.Min, bb.Max))
|
|
return false;
|
|
if (g.NavDisableMouseHover)
|
|
return false;
|
|
if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled))
|
|
{
|
|
g.HoveredIdDisabled = true;
|
|
return false;
|
|
}
|
|
|
|
if (id != 0)
|
|
{
|
|
SetHoveredID(id);
|
|
|
|
if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
|
|
GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
|
|
if (g.DebugItemPickerBreakId == id)
|
|
IM_DEBUG_BREAK();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (!bb.Overlaps(window->ClipRect))
|
|
if (id == 0 || (id != g.ActiveId && id != g.NavId))
|
|
if (clip_even_when_logged || !g.LogEnabled)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
|
|
{
|
|
window->DC.LastItemId = item_id;
|
|
window->DC.LastItemStatusFlags = item_flags;
|
|
window->DC.LastItemRect = item_rect;
|
|
}
|
|
|
|
bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
|
|
window->DC.FocusCounterRegular++;
|
|
if (is_tab_stop)
|
|
window->DC.FocusCounterTabStop++;
|
|
|
|
if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL)
|
|
{
|
|
g.FocusRequestNextWindow = window;
|
|
g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1);
|
|
}
|
|
|
|
if (g.FocusRequestCurrWindow == window)
|
|
{
|
|
if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular)
|
|
return true;
|
|
if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop)
|
|
{
|
|
g.NavJustTabbedId = id;
|
|
return true;
|
|
}
|
|
|
|
if (g.ActiveId == id)
|
|
ClearActiveID();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ImGui::FocusableItemUnregister(ImGuiWindow* window)
|
|
{
|
|
window->DC.FocusCounterRegular--;
|
|
window->DC.FocusCounterTabStop--;
|
|
}
|
|
|
|
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
|
{
|
|
if (wrap_pos_x < 0.0f)
|
|
return 0.0f;
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (wrap_pos_x == 0.0f)
|
|
{
|
|
wrap_pos_x = window->WorkRect.Max.x;
|
|
}
|
|
else if (wrap_pos_x > 0.0f)
|
|
{
|
|
wrap_pos_x += window->Pos.x - window->Scroll.x;
|
|
}
|
|
|
|
return ImMax(wrap_pos_x - pos.x, 1.0f);
|
|
}
|
|
|
|
void* ImGui::MemAlloc(size_t size)
|
|
{
|
|
if (ImGuiContext* ctx = GImGui)
|
|
ctx->IO.MetricsActiveAllocations++;
|
|
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
|
|
}
|
|
|
|
void ImGui::MemFree(void* ptr)
|
|
{
|
|
if (ptr)
|
|
if (ImGuiContext* ctx = GImGui)
|
|
ctx->IO.MetricsActiveAllocations--;
|
|
return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
|
|
}
|
|
|
|
const char* ImGui::GetClipboardText()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
|
|
}
|
|
|
|
void ImGui::SetClipboardText(const char* text)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.IO.SetClipboardTextFn)
|
|
g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
|
|
}
|
|
|
|
const char* ImGui::GetVersion()
|
|
{
|
|
return IMGUI_VERSION;
|
|
}
|
|
|
|
ImGuiContext* ImGui::GetCurrentContext()
|
|
{
|
|
return GImGui;
|
|
}
|
|
|
|
void ImGui::SetCurrentContext(ImGuiContext* ctx)
|
|
{
|
|
#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
|
|
IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx);
|
|
#else
|
|
GImGui = ctx;
|
|
#endif
|
|
}
|
|
|
|
void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
|
|
{
|
|
GImAllocatorAllocFunc = alloc_func;
|
|
GImAllocatorFreeFunc = free_func;
|
|
GImAllocatorUserData = user_data;
|
|
}
|
|
|
|
ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
|
|
{
|
|
ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
|
|
if (GImGui == NULL)
|
|
SetCurrentContext(ctx);
|
|
Initialize(ctx);
|
|
return ctx;
|
|
}
|
|
|
|
void ImGui::DestroyContext(ImGuiContext* ctx)
|
|
{
|
|
if (ctx == NULL)
|
|
ctx = GImGui;
|
|
Shutdown(ctx);
|
|
if (GImGui == ctx)
|
|
SetCurrentContext(NULL);
|
|
IM_DELETE(ctx);
|
|
}
|
|
|
|
ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);
|
|
g.Hooks.push_back(*hook);
|
|
g.Hooks.back().HookId = ++g.HookIdNext;
|
|
return g.HookIdNext;
|
|
}
|
|
|
|
void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
IM_ASSERT(hook_id != 0);
|
|
for (int n = 0; n < g.Hooks.Size; n++)
|
|
if (g.Hooks[n].HookId == hook_id)
|
|
g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_;
|
|
}
|
|
|
|
void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
for (int n = 0; n < g.Hooks.Size; n++)
|
|
if (g.Hooks[n].Type == hook_type)
|
|
g.Hooks[n].Callback(&g, &g.Hooks[n]);
|
|
}
|
|
|
|
ImGuiIO& ImGui::GetIO()
|
|
{
|
|
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
|
|
return GImGui->IO;
|
|
}
|
|
|
|
ImDrawData* ImGui::GetDrawData()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.DrawData.Valid ? &g.DrawData : NULL;
|
|
}
|
|
|
|
double ImGui::GetTime()
|
|
{
|
|
return GImGui->Time;
|
|
}
|
|
|
|
int ImGui::GetFrameCount()
|
|
{
|
|
return GImGui->FrameCount;
|
|
}
|
|
|
|
ImDrawList* ImGui::GetBackgroundDrawList()
|
|
{
|
|
return &GImGui->BackgroundDrawList;
|
|
}
|
|
|
|
ImDrawList* ImGui::GetForegroundDrawList()
|
|
{
|
|
return &GImGui->ForegroundDrawList;
|
|
}
|
|
|
|
ImDrawListSharedData* ImGui::GetDrawListSharedData()
|
|
{
|
|
return &GImGui->DrawListSharedData;
|
|
}
|
|
|
|
void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
FocusWindow(window);
|
|
SetActiveID(window->MoveId, window);
|
|
g.NavDisableHighlight = true;
|
|
g.ActiveIdNoClearOnFocusLoss = true;
|
|
g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
|
|
|
|
bool can_move_window = true;
|
|
if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
|
|
can_move_window = false;
|
|
if (can_move_window)
|
|
g.MovingWindow = window;
|
|
}
|
|
|
|
void ImGui::UpdateMouseMovingWindowNewFrame()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.MovingWindow != NULL)
|
|
{
|
|
KeepAliveID(g.ActiveId);
|
|
IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
|
|
ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
|
|
if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
|
|
{
|
|
ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
|
|
if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
|
|
{
|
|
MarkIniSettingsDirty(moving_window);
|
|
SetWindowPos(moving_window, pos, ImGuiCond_Always);
|
|
}
|
|
FocusWindow(g.MovingWindow);
|
|
}
|
|
else
|
|
{
|
|
ClearActiveID();
|
|
g.MovingWindow = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
|
|
{
|
|
KeepAliveID(g.ActiveId);
|
|
if (!g.IO.MouseDown[0])
|
|
ClearActiveID();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImGui::UpdateMouseMovingWindowEndFrame()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.ActiveId != 0 || g.HoveredId != 0)
|
|
return;
|
|
|
|
if (g.NavWindow && g.NavWindow->Appearing)
|
|
return;
|
|
|
|
if (g.IO.MouseClicked[0])
|
|
{
|
|
ImGuiWindow* root_window = g.HoveredRootWindow;
|
|
const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
|
|
|
|
if (root_window != NULL && !is_closed_popup)
|
|
{
|
|
StartMouseMovingWindow(g.HoveredWindow);
|
|
|
|
if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
|
|
g.MovingWindow = NULL;
|
|
|
|
if (g.HoveredIdDisabled)
|
|
g.MovingWindow = NULL;
|
|
}
|
|
else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
|
|
{
|
|
FocusWindow(NULL);
|
|
}
|
|
}
|
|
|
|
if (g.IO.MouseClicked[1])
|
|
{
|
|
ImGuiWindow* modal = GetTopMostPopupModal();
|
|
bool hovered_window_above_modal = g.HoveredWindow && IsWindowAbove(g.HoveredWindow, modal);
|
|
ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
|
|
}
|
|
}
|
|
|
|
static bool IsWindowActiveAndVisible(ImGuiWindow* window)
|
|
{
|
|
return (window->Active) && (!window->Hidden);
|
|
}
|
|
|
|
static void ImGui::UpdateMouseInputs()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (IsMousePosValid(&g.IO.MousePos))
|
|
g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
|
|
|
|
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
|
|
g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
|
|
else
|
|
g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
|
|
if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
|
|
g.NavDisableMouseHover = false;
|
|
|
|
g.IO.MousePosPrev = g.IO.MousePos;
|
|
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
|
|
{
|
|
g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
|
|
g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
|
|
g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
|
|
g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f;
|
|
g.IO.MouseDoubleClicked[i] = false;
|
|
if (g.IO.MouseClicked[i])
|
|
{
|
|
if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
|
|
{
|
|
ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
|
|
if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
|
|
g.IO.MouseDoubleClicked[i] = true;
|
|
g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f;
|
|
}
|
|
else
|
|
{
|
|
g.IO.MouseClickedTime[i] = g.Time;
|
|
}
|
|
g.IO.MouseClickedPos[i] = g.IO.MousePos;
|
|
g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i];
|
|
g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
|
|
g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
|
|
}
|
|
else if (g.IO.MouseDown[i])
|
|
{
|
|
ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
|
|
g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
|
|
g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x);
|
|
g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y);
|
|
}
|
|
if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i])
|
|
g.IO.MouseDownWasDoubleClick[i] = false;
|
|
if (g.IO.MouseClicked[i])
|
|
g.NavDisableMouseHover = false;
|
|
}
|
|
}
|
|
|
|
static void StartLockWheelingWindow(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.WheelingWindow == window)
|
|
return;
|
|
g.WheelingWindow = window;
|
|
g.WheelingWindowRefMousePos = g.IO.MousePos;
|
|
g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
|
|
}
|
|
|
|
void ImGui::UpdateMouseWheel()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (g.WheelingWindow != NULL)
|
|
{
|
|
g.WheelingWindowTimer -= g.IO.DeltaTime;
|
|
if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
|
|
g.WheelingWindowTimer = 0.0f;
|
|
if (g.WheelingWindowTimer <= 0.0f)
|
|
{
|
|
g.WheelingWindow = NULL;
|
|
g.WheelingWindowTimer = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
|
|
return;
|
|
|
|
if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel))
|
|
return;
|
|
|
|
ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
|
|
if (!window || window->Collapsed)
|
|
return;
|
|
|
|
if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
|
|
{
|
|
StartLockWheelingWindow(window);
|
|
const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
|
|
const float scale = new_font_scale / window->FontWindowScale;
|
|
window->FontWindowScale = new_font_scale;
|
|
if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
{
|
|
const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
|
|
SetWindowPos(window, window->Pos + offset, 0);
|
|
window->Size = ImFloor(window->Size * scale);
|
|
window->SizeFull = ImFloor(window->SizeFull * scale);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
|
|
if (wheel_y != 0.0f && !g.IO.KeyCtrl)
|
|
{
|
|
StartLockWheelingWindow(window);
|
|
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
|
|
window = window->ParentWindow;
|
|
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
|
|
{
|
|
float max_step = window->InnerRect.GetHeight() * 0.67f;
|
|
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
|
|
SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
|
|
}
|
|
}
|
|
|
|
const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
|
|
if (wheel_x != 0.0f && !g.IO.KeyCtrl)
|
|
{
|
|
StartLockWheelingWindow(window);
|
|
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
|
|
window = window->ParentWindow;
|
|
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
|
|
{
|
|
float max_step = window->InnerRect.GetWidth() * 0.67f;
|
|
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
|
|
SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImGui::UpdateTabFocus()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
|
|
if (g.ActiveId == 0 && g.FocusTabPressed)
|
|
{
|
|
g.FocusRequestNextWindow = g.NavWindow;
|
|
g.FocusRequestNextCounterRegular = INT_MAX;
|
|
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
|
|
g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
|
|
else
|
|
g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
|
|
}
|
|
|
|
g.FocusRequestCurrWindow = NULL;
|
|
g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
|
|
if (g.FocusRequestNextWindow != NULL)
|
|
{
|
|
ImGuiWindow* window = g.FocusRequestNextWindow;
|
|
g.FocusRequestCurrWindow = window;
|
|
if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
|
|
g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
|
|
if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
|
|
g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
|
|
g.FocusRequestNextWindow = NULL;
|
|
g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
|
|
}
|
|
|
|
g.NavIdTabCounter = INT_MAX;
|
|
}
|
|
|
|
void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
bool clear_hovered_windows = false;
|
|
FindHoveredWindow();
|
|
|
|
ImGuiWindow* modal_window = GetTopMostPopupModal();
|
|
if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
|
|
clear_hovered_windows = true;
|
|
|
|
if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
|
|
clear_hovered_windows = true;
|
|
|
|
int mouse_earliest_button_down = -1;
|
|
bool mouse_any_down = false;
|
|
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
|
|
{
|
|
if (g.IO.MouseClicked[i])
|
|
g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0);
|
|
mouse_any_down |= g.IO.MouseDown[i];
|
|
if (g.IO.MouseDown[i])
|
|
if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
|
|
mouse_earliest_button_down = i;
|
|
}
|
|
const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
|
|
|
|
const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
|
|
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
|
|
clear_hovered_windows = true;
|
|
|
|
if (clear_hovered_windows)
|
|
g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
|
|
|
|
if (g.WantCaptureMouseNextFrame != -1)
|
|
g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
|
|
else
|
|
g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0);
|
|
|
|
if (g.WantCaptureKeyboardNextFrame != -1)
|
|
g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
|
|
else
|
|
g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
|
|
if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
|
|
g.IO.WantCaptureKeyboard = true;
|
|
|
|
g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
|
|
}
|
|
|
|
ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
|
|
if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
|
|
if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; }
|
|
if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; }
|
|
if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; }
|
|
return key_mod_flags;
|
|
}
|
|
|
|
void ImGui::NewFrame()
|
|
{
|
|
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
for (int n = g.Hooks.Size - 1; n >= 0; n--)
|
|
if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_)
|
|
g.Hooks.erase(&g.Hooks[n]);
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_NewFramePre);
|
|
|
|
ErrorCheckNewFrameSanityChecks();
|
|
|
|
UpdateSettings();
|
|
|
|
g.Time += g.IO.DeltaTime;
|
|
g.WithinFrameScope = true;
|
|
g.FrameCount += 1;
|
|
g.TooltipOverrideCount = 0;
|
|
g.WindowsActiveCount = 0;
|
|
g.MenusIdSubmittedThisFrame.resize(0);
|
|
|
|
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
|
|
g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
|
|
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
|
|
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
|
|
|
|
g.IO.Fonts->Locked = true;
|
|
SetCurrentFont(GetDefaultFont());
|
|
IM_ASSERT(g.Font->IsLoaded());
|
|
g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
|
|
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
|
|
g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError);
|
|
g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
|
|
if (g.Style.AntiAliasedLines)
|
|
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
|
|
if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))
|
|
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
|
|
if (g.Style.AntiAliasedFill)
|
|
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
|
|
if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
|
|
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
|
|
|
|
g.BackgroundDrawList._ResetForNewFrame();
|
|
g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
|
|
g.BackgroundDrawList.PushClipRectFullScreen();
|
|
|
|
g.ForegroundDrawList._ResetForNewFrame();
|
|
g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
|
|
g.ForegroundDrawList.PushClipRectFullScreen();
|
|
|
|
g.DrawData.Clear();
|
|
|
|
if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
|
|
KeepAliveID(g.DragDropPayload.SourceId);
|
|
|
|
if (!g.HoveredIdPreviousFrame)
|
|
g.HoveredIdTimer = 0.0f;
|
|
if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
|
|
g.HoveredIdNotActiveTimer = 0.0f;
|
|
if (g.HoveredId)
|
|
g.HoveredIdTimer += g.IO.DeltaTime;
|
|
if (g.HoveredId && g.ActiveId != g.HoveredId)
|
|
g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
|
|
g.HoveredIdPreviousFrame = g.HoveredId;
|
|
g.HoveredIdPreviousFrameUsingMouseWheel = g.HoveredIdUsingMouseWheel;
|
|
g.HoveredId = 0;
|
|
g.HoveredIdAllowOverlap = false;
|
|
g.HoveredIdUsingMouseWheel = false;
|
|
g.HoveredIdDisabled = false;
|
|
|
|
if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
|
|
ClearActiveID();
|
|
if (g.ActiveId)
|
|
g.ActiveIdTimer += g.IO.DeltaTime;
|
|
g.LastActiveIdTimer += g.IO.DeltaTime;
|
|
g.ActiveIdPreviousFrame = g.ActiveId;
|
|
g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
|
|
g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
|
|
g.ActiveIdIsAlive = 0;
|
|
g.ActiveIdHasBeenEditedThisFrame = false;
|
|
g.ActiveIdPreviousFrameIsAlive = false;
|
|
g.ActiveIdIsJustActivated = false;
|
|
if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
|
|
g.TempInputId = 0;
|
|
if (g.ActiveId == 0)
|
|
{
|
|
g.ActiveIdUsingNavDirMask = 0x00;
|
|
g.ActiveIdUsingNavInputMask = 0x00;
|
|
g.ActiveIdUsingKeyInputMask = 0x00;
|
|
}
|
|
|
|
g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
|
|
g.DragDropAcceptIdCurr = 0;
|
|
g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
|
|
g.DragDropWithinSource = false;
|
|
g.DragDropWithinTarget = false;
|
|
g.DragDropHoldJustPressedId = 0;
|
|
|
|
g.IO.KeyMods = GetMergedKeyModFlags();
|
|
memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
|
|
for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
|
|
g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f;
|
|
|
|
NavUpdate();
|
|
|
|
UpdateMouseInputs();
|
|
|
|
UpdateHoveredWindowAndCaptureFlags();
|
|
|
|
UpdateMouseMovingWindowNewFrame();
|
|
|
|
if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
|
|
g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
|
|
else
|
|
g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
|
|
|
|
g.MouseCursor = ImGuiMouseCursor_Arrow;
|
|
g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
|
|
g.PlatformImePos = ImVec2(1.0f, 1.0f);
|
|
|
|
UpdateMouseWheel();
|
|
|
|
UpdateTabFocus();
|
|
|
|
IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
|
|
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
{
|
|
ImGuiWindow* window = g.Windows[i];
|
|
window->WasActive = window->Active;
|
|
window->BeginCount = 0;
|
|
window->Active = false;
|
|
window->WriteAccessed = false;
|
|
|
|
if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
|
|
GcCompactTransientWindowBuffers(window);
|
|
}
|
|
|
|
for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
|
|
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
|
|
TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
|
|
if (g.GcCompactAll)
|
|
GcCompactTransientMiscBuffers();
|
|
g.GcCompactAll = false;
|
|
|
|
if (g.NavWindow && !g.NavWindow->WasActive)
|
|
FocusTopMostWindowUnderOne(NULL, NULL);
|
|
|
|
g.CurrentWindowStack.resize(0);
|
|
g.BeginPopupStack.resize(0);
|
|
g.ItemFlagsStack.resize(0);
|
|
g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_);
|
|
g.GroupStack.resize(0);
|
|
ClosePopupsOverWindow(g.NavWindow, false);
|
|
|
|
UpdateDebugToolItemPicker();
|
|
|
|
g.WithinFrameScopeWithImplicitWindow = true;
|
|
SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
|
|
Begin("Debug##Default");
|
|
IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
|
|
}
|
|
|
|
void ImGui::UpdateDebugToolItemPicker()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.DebugItemPickerBreakId = 0;
|
|
if (g.DebugItemPickerActive)
|
|
{
|
|
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
|
|
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
|
if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
|
|
g.DebugItemPickerActive = false;
|
|
if (ImGui::IsMouseClicked(0) && hovered_id)
|
|
{
|
|
g.DebugItemPickerBreakId = hovered_id;
|
|
g.DebugItemPickerActive = false;
|
|
}
|
|
ImGui::SetNextWindowBgAlpha(0.60f);
|
|
ImGui::BeginTooltip();
|
|
ImGui::Text("HoveredId: 0x%08X", hovered_id);
|
|
ImGui::Text("Press ESC to abort picking.");
|
|
ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
|
|
ImGui::EndTooltip();
|
|
}
|
|
}
|
|
|
|
void ImGui::Initialize(ImGuiContext* context)
|
|
{
|
|
ImGuiContext& g = *context;
|
|
IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
|
|
|
|
{
|
|
ImGuiSettingsHandler ini_handler;
|
|
ini_handler.TypeName = "Window";
|
|
ini_handler.TypeHash = ImHashStr("Window");
|
|
ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
|
|
ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
|
|
ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
|
|
ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
|
|
ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
|
|
g.SettingsHandlers.push_back(ini_handler);
|
|
}
|
|
|
|
#ifdef IMGUI_HAS_TABLE
|
|
TableSettingsInstallHandler(context);
|
|
#endif
|
|
|
|
#ifdef IMGUI_HAS_DOCK
|
|
#endif
|
|
|
|
g.Initialized = true;
|
|
}
|
|
|
|
void ImGui::Shutdown(ImGuiContext* context)
|
|
{
|
|
ImGuiContext& g = *context;
|
|
if (g.IO.Fonts && g.FontAtlasOwnedByContext)
|
|
{
|
|
g.IO.Fonts->Locked = false;
|
|
IM_DELETE(g.IO.Fonts);
|
|
}
|
|
g.IO.Fonts = NULL;
|
|
|
|
if (!g.Initialized)
|
|
return;
|
|
|
|
if (g.SettingsLoaded && g.IO.IniFilename != NULL)
|
|
{
|
|
ImGuiContext* backup_context = GImGui;
|
|
SetCurrentContext(&g);
|
|
SaveIniSettingsToDisk(g.IO.IniFilename);
|
|
SetCurrentContext(backup_context);
|
|
}
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_Shutdown);
|
|
|
|
for (int i = 0; i < g.Windows.Size; i++)
|
|
IM_DELETE(g.Windows[i]);
|
|
g.Windows.clear();
|
|
g.WindowsFocusOrder.clear();
|
|
g.WindowsTempSortBuffer.clear();
|
|
g.CurrentWindow = NULL;
|
|
g.CurrentWindowStack.clear();
|
|
g.WindowsById.Clear();
|
|
g.NavWindow = NULL;
|
|
g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
|
|
g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
|
|
g.MovingWindow = NULL;
|
|
g.ColorStack.clear();
|
|
g.StyleVarStack.clear();
|
|
g.FontStack.clear();
|
|
g.OpenPopupStack.clear();
|
|
g.BeginPopupStack.clear();
|
|
g.DrawDataBuilder.ClearFreeMemory();
|
|
g.BackgroundDrawList._ClearFreeMemory();
|
|
g.ForegroundDrawList._ClearFreeMemory();
|
|
|
|
g.TabBars.Clear();
|
|
g.CurrentTabBarStack.clear();
|
|
g.ShrinkWidthBuffer.clear();
|
|
|
|
g.Tables.Clear();
|
|
g.CurrentTableStack.clear();
|
|
g.DrawChannelsTempMergeBuffer.clear();
|
|
|
|
g.ClipboardHandlerData.clear();
|
|
g.MenusIdSubmittedThisFrame.clear();
|
|
g.InputTextState.ClearFreeMemory();
|
|
|
|
g.SettingsWindows.clear();
|
|
g.SettingsHandlers.clear();
|
|
|
|
if (g.LogFile)
|
|
{
|
|
#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
|
|
if (g.LogFile != stdout)
|
|
#endif
|
|
ImFileClose(g.LogFile);
|
|
g.LogFile = NULL;
|
|
}
|
|
g.LogBuffer.clear();
|
|
|
|
g.Initialized = false;
|
|
}
|
|
|
|
static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
|
|
{
|
|
const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
|
|
const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
|
|
if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
|
|
return d;
|
|
if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
|
|
return d;
|
|
return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
|
|
}
|
|
|
|
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
|
|
{
|
|
out_sorted_windows->push_back(window);
|
|
if (window->Active)
|
|
{
|
|
int count = window->DC.ChildWindows.Size;
|
|
if (count > 1)
|
|
ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
ImGuiWindow* child = window->DC.ChildWindows[i];
|
|
if (child->Active)
|
|
AddWindowToSortBuffer(out_sorted_windows, child);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
|
|
{
|
|
draw_list->_PopUnusedDrawCmd();
|
|
if (draw_list->CmdBuffer.Size == 0)
|
|
return;
|
|
|
|
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
|
|
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
|
|
if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
|
|
IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
|
|
|
|
if (sizeof(ImDrawIdx) == 2)
|
|
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
|
|
|
|
out_list->push_back(draw_list);
|
|
}
|
|
|
|
static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.IO.MetricsRenderWindows++;
|
|
AddDrawListToDrawData(out_render_list, window->DrawList);
|
|
for (int i = 0; i < window->DC.ChildWindows.Size; i++)
|
|
{
|
|
ImGuiWindow* child = window->DC.ChildWindows[i];
|
|
if (IsWindowActiveAndVisible(child))
|
|
AddWindowToDrawData(out_render_list, child);
|
|
}
|
|
}
|
|
|
|
static void AddRootWindowToDrawData(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
|
|
AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window);
|
|
}
|
|
|
|
void ImDrawDataBuilder::FlattenIntoSingleLayer()
|
|
{
|
|
int n = Layers[0].Size;
|
|
int size = n;
|
|
for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
|
|
size += Layers[i].Size;
|
|
Layers[0].resize(size);
|
|
for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
|
|
{
|
|
ImVector<ImDrawList*>& layer = Layers[layer_n];
|
|
if (layer.empty())
|
|
continue;
|
|
memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
|
|
n += layer.Size;
|
|
layer.resize(0);
|
|
}
|
|
}
|
|
|
|
static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data)
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
draw_data->Valid = true;
|
|
draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
|
|
draw_data->CmdListsCount = draw_lists->Size;
|
|
draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
|
|
draw_data->DisplayPos = ImVec2(0.0f, 0.0f);
|
|
draw_data->DisplaySize = io.DisplaySize;
|
|
draw_data->FramebufferScale = io.DisplayFramebufferScale;
|
|
for (int n = 0; n < draw_lists->Size; n++)
|
|
{
|
|
draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
|
|
draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
|
|
}
|
|
}
|
|
|
|
void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
|
|
window->ClipRect = window->DrawList->_ClipRectStack.back();
|
|
}
|
|
|
|
void ImGui::PopClipRect()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DrawList->PopClipRect();
|
|
window->ClipRect = window->DrawList->_ClipRectStack.back();
|
|
}
|
|
|
|
void ImGui::EndFrame()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.Initialized);
|
|
|
|
if (g.FrameCountEnded == g.FrameCount)
|
|
return;
|
|
IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
|
|
|
|
ErrorCheckEndFrameSanityChecks();
|
|
|
|
if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
|
|
{
|
|
g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
|
|
g.PlatformImeLastPos = g.PlatformImePos;
|
|
}
|
|
|
|
g.WithinFrameScopeWithImplicitWindow = false;
|
|
if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
|
|
g.CurrentWindow->Active = false;
|
|
End();
|
|
|
|
NavEndFrame();
|
|
|
|
if (g.DragDropActive)
|
|
{
|
|
bool is_delivered = g.DragDropPayload.Delivery;
|
|
bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
|
|
if (is_delivered || is_elapsed)
|
|
ClearDragDrop();
|
|
}
|
|
|
|
if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
|
|
{
|
|
g.DragDropWithinSource = true;
|
|
SetTooltip("...");
|
|
g.DragDropWithinSource = false;
|
|
}
|
|
|
|
g.WithinFrameScope = false;
|
|
g.FrameCountEnded = g.FrameCount;
|
|
|
|
UpdateMouseMovingWindowEndFrame();
|
|
|
|
g.WindowsTempSortBuffer.resize(0);
|
|
g.WindowsTempSortBuffer.reserve(g.Windows.Size);
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
{
|
|
ImGuiWindow* window = g.Windows[i];
|
|
if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
continue;
|
|
AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
|
|
}
|
|
|
|
IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);
|
|
g.Windows.swap(g.WindowsTempSortBuffer);
|
|
g.IO.MetricsActiveWindows = g.WindowsActiveCount;
|
|
|
|
g.IO.Fonts->Locked = false;
|
|
|
|
g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
|
|
g.IO.InputQueueCharacters.resize(0);
|
|
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_EndFramePost);
|
|
}
|
|
|
|
void ImGui::Render()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.Initialized);
|
|
|
|
if (g.FrameCountEnded != g.FrameCount)
|
|
EndFrame();
|
|
g.FrameCountRendered = g.FrameCount;
|
|
g.IO.MetricsRenderWindows = 0;
|
|
g.DrawDataBuilder.Clear();
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_RenderPre);
|
|
|
|
if (!g.BackgroundDrawList.VtxBuffer.empty())
|
|
AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList);
|
|
|
|
ImGuiWindow* windows_to_render_top_most[2];
|
|
windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
|
|
windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
|
|
for (int n = 0; n != g.Windows.Size; n++)
|
|
{
|
|
ImGuiWindow* window = g.Windows[n];
|
|
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
|
|
AddRootWindowToDrawData(window);
|
|
}
|
|
for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
|
|
if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n]))
|
|
AddRootWindowToDrawData(windows_to_render_top_most[n]);
|
|
g.DrawDataBuilder.FlattenIntoSingleLayer();
|
|
|
|
if (g.IO.MouseDrawCursor)
|
|
RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
|
|
|
|
if (!g.ForegroundDrawList.VtxBuffer.empty())
|
|
AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList);
|
|
|
|
SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
|
|
g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
|
|
g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
|
|
|
|
CallContextHooks(&g, ImGuiContextHookType_RenderPost);
|
|
}
|
|
|
|
ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
const char* text_display_end;
|
|
if (hide_text_after_double_hash)
|
|
text_display_end = FindRenderedTextEnd(text, text_end);
|
|
else
|
|
text_display_end = text_end;
|
|
|
|
ImFont* font = g.Font;
|
|
const float font_size = g.FontSize;
|
|
if (text == text_display_end)
|
|
return ImVec2(0.0f, font_size);
|
|
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
|
|
|
|
text_size.x = IM_FLOOR(text_size.x + 0.99999f);
|
|
|
|
return text_size;
|
|
}
|
|
|
|
static void FindHoveredWindow()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
ImGuiWindow* hovered_window = NULL;
|
|
ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
|
|
if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
|
|
hovered_window = g.MovingWindow;
|
|
|
|
ImVec2 padding_regular = g.Style.TouchExtraPadding;
|
|
ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
|
|
for (int i = g.Windows.Size - 1; i >= 0; i--)
|
|
{
|
|
ImGuiWindow* window = g.Windows[i];
|
|
if (!window->Active || window->Hidden)
|
|
continue;
|
|
if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
|
|
continue;
|
|
|
|
ImRect bb(window->OuterRectClipped);
|
|
if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
|
|
bb.Expand(padding_regular);
|
|
else
|
|
bb.Expand(padding_for_resize_from_edges);
|
|
if (!bb.Contains(g.IO.MousePos))
|
|
continue;
|
|
|
|
if (window->HitTestHoleSize.x != 0)
|
|
{
|
|
ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
|
|
ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
|
|
if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))
|
|
continue;
|
|
}
|
|
|
|
if (hovered_window == NULL)
|
|
hovered_window = window;
|
|
if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
|
|
hovered_window_ignoring_moving_window = window;
|
|
if (hovered_window && hovered_window_ignoring_moving_window)
|
|
break;
|
|
}
|
|
|
|
g.HoveredWindow = hovered_window;
|
|
g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
|
|
g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
|
|
}
|
|
|
|
bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
ImRect rect_clipped(r_min, r_max);
|
|
if (clip)
|
|
rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
|
|
|
|
const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
|
|
if (!rect_for_touch.Contains(g.IO.MousePos))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
int ImGui::GetKeyIndex(ImGuiKey imgui_key)
|
|
{
|
|
IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
|
|
ImGuiContext& g = *GImGui;
|
|
return g.IO.KeyMap[imgui_key];
|
|
}
|
|
|
|
bool ImGui::IsKeyDown(int user_key_index)
|
|
{
|
|
if (user_key_index < 0)
|
|
return false;
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
|
|
return g.IO.KeysDown[user_key_index];
|
|
}
|
|
|
|
int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
|
|
{
|
|
if (t1 == 0.0f)
|
|
return 1;
|
|
if (t0 >= t1)
|
|
return 0;
|
|
if (repeat_rate <= 0.0f)
|
|
return (t0 < repeat_delay) && (t1 >= repeat_delay);
|
|
const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
|
|
const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
|
|
const int count = count_t1 - count_t0;
|
|
return count;
|
|
}
|
|
|
|
int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (key_index < 0)
|
|
return 0;
|
|
IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
|
|
const float t = g.IO.KeysDownDuration[key_index];
|
|
return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
|
|
}
|
|
|
|
bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (user_key_index < 0)
|
|
return false;
|
|
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
|
|
const float t = g.IO.KeysDownDuration[user_key_index];
|
|
if (t == 0.0f)
|
|
return true;
|
|
if (repeat && t > g.IO.KeyRepeatDelay)
|
|
return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsKeyReleased(int user_key_index)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (user_key_index < 0) return false;
|
|
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
|
|
return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
|
|
}
|
|
|
|
bool ImGui::IsMouseDown(ImGuiMouseButton button)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
return g.IO.MouseDown[button];
|
|
}
|
|
|
|
bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
const float t = g.IO.MouseDownDuration[button];
|
|
if (t == 0.0f)
|
|
return true;
|
|
|
|
if (repeat && t > g.IO.KeyRepeatDelay)
|
|
{
|
|
int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
|
|
if (amount > 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsMouseReleased(ImGuiMouseButton button)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
return g.IO.MouseReleased[button];
|
|
}
|
|
|
|
bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
return g.IO.MouseDoubleClicked[button];
|
|
}
|
|
|
|
bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
if (lock_threshold < 0.0f)
|
|
lock_threshold = g.IO.MouseDragThreshold;
|
|
return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
|
|
}
|
|
|
|
bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
if (!g.IO.MouseDown[button])
|
|
return false;
|
|
return IsMouseDragPastThreshold(button, lock_threshold);
|
|
}
|
|
|
|
ImVec2 ImGui::GetMousePos()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.IO.MousePos;
|
|
}
|
|
|
|
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.BeginPopupStack.Size > 0)
|
|
return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
|
|
return g.IO.MousePos;
|
|
}
|
|
|
|
bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
|
|
{
|
|
IM_ASSERT(GImGui != NULL);
|
|
const float MOUSE_INVALID = -256000.0f;
|
|
ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
|
|
return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
|
|
}
|
|
|
|
bool ImGui::IsAnyMouseDown()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
|
|
if (g.IO.MouseDown[n])
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
if (lock_threshold < 0.0f)
|
|
lock_threshold = g.IO.MouseDragThreshold;
|
|
if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
|
|
if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
|
|
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
|
|
return g.IO.MousePos - g.IO.MouseClickedPos[button];
|
|
return ImVec2(0.0f, 0.0f);
|
|
}
|
|
|
|
void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
|
|
g.IO.MouseClickedPos[button] = g.IO.MousePos;
|
|
}
|
|
|
|
ImGuiMouseCursor ImGui::GetMouseCursor()
|
|
{
|
|
return GImGui->MouseCursor;
|
|
}
|
|
|
|
void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
|
|
{
|
|
GImGui->MouseCursor = cursor_type;
|
|
}
|
|
|
|
void ImGui::CaptureKeyboardFromApp(bool capture)
|
|
{
|
|
GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
|
|
}
|
|
|
|
void ImGui::CaptureMouseFromApp(bool capture)
|
|
{
|
|
GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
|
|
}
|
|
|
|
bool ImGui::IsItemActive()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.ActiveId)
|
|
{
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
return g.ActiveId == window->DC.LastItemId;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsItemActivated()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.ActiveId)
|
|
{
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsItemDeactivated()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
|
|
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
|
|
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
|
|
}
|
|
|
|
bool ImGui::IsItemDeactivatedAfterEdit()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
|
|
}
|
|
|
|
bool ImGui::IsItemFocused()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
if (g.NavId != window->DC.LastItemId || g.NavId == 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
|
|
{
|
|
return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
|
|
}
|
|
|
|
bool ImGui::IsItemToggledOpen()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
|
|
}
|
|
|
|
bool ImGui::IsItemToggledSelection()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
|
|
}
|
|
|
|
bool ImGui::IsAnyItemHovered()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
|
|
}
|
|
|
|
bool ImGui::IsAnyItemActive()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.ActiveId != 0;
|
|
}
|
|
|
|
bool ImGui::IsAnyItemFocused()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.NavId != 0 && !g.NavDisableHighlight;
|
|
}
|
|
|
|
bool ImGui::IsItemVisible()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->ClipRect.Overlaps(window->DC.LastItemRect);
|
|
}
|
|
|
|
bool ImGui::IsItemEdited()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
|
|
}
|
|
|
|
void ImGui::SetItemAllowOverlap()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiID id = g.CurrentWindow->DC.LastItemId;
|
|
if (g.HoveredId == id)
|
|
g.HoveredIdAllowOverlap = true;
|
|
if (g.ActiveId == id)
|
|
g.ActiveIdAllowOverlap = true;
|
|
}
|
|
|
|
void ImGui::SetItemUsingMouseWheel()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiID id = g.CurrentWindow->DC.LastItemId;
|
|
if (g.HoveredId == id)
|
|
g.HoveredIdUsingMouseWheel = true;
|
|
if (g.ActiveId == id)
|
|
g.ActiveIdUsingMouseWheel = true;
|
|
}
|
|
|
|
ImVec2 ImGui::GetItemRectMin()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.LastItemRect.Min;
|
|
}
|
|
|
|
ImVec2 ImGui::GetItemRectMax()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.LastItemRect.Max;
|
|
}
|
|
|
|
ImVec2 ImGui::GetItemRectSize()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.LastItemRect.GetSize();
|
|
}
|
|
|
|
static ImRect GetViewportRect()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
|
|
}
|
|
|
|
bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* parent_window = g.CurrentWindow;
|
|
|
|
flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;
|
|
flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);
|
|
|
|
const ImVec2 content_avail = GetContentRegionAvail();
|
|
ImVec2 size = ImFloor(size_arg);
|
|
const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
|
|
if (size.x <= 0.0f)
|
|
size.x = ImMax(content_avail.x + size.x, 4.0f);
|
|
if (size.y <= 0.0f)
|
|
size.y = ImMax(content_avail.y + size.y, 4.0f);
|
|
SetNextWindowSize(size);
|
|
|
|
if (name)
|
|
ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%s_%08X", parent_window->Name, name, id);
|
|
else
|
|
ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%08X", parent_window->Name, id);
|
|
|
|
const float backup_border_size = g.Style.ChildBorderSize;
|
|
if (!border)
|
|
g.Style.ChildBorderSize = 0.0f;
|
|
bool ret = Begin(g.TempBuffer, NULL, flags);
|
|
g.Style.ChildBorderSize = backup_border_size;
|
|
|
|
|
|
ImGuiWindow* child_window = g.CurrentWindow;
|
|
child_window->ChildId = id;
|
|
child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
|
|
|
|
if (child_window->BeginCount == 1)
|
|
parent_window->DC.CursorPos = child_window->Pos;
|
|
|
|
if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
|
|
{
|
|
FocusWindow(child_window);
|
|
NavInitWindow(child_window, false);
|
|
SetActiveID(id + 1, child_window);
|
|
g.ActiveIdSource = ImGuiInputSource_Nav;
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
|
|
}
|
|
|
|
bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
|
|
{
|
|
IM_ASSERT(id != 0);
|
|
return BeginChildEx(NULL, id, size_arg, border, extra_flags);
|
|
}
|
|
|
|
void ImGui::EndChild()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
IM_ASSERT(g.WithinEndChild == false);
|
|
IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);
|
|
|
|
g.WithinEndChild = true;
|
|
if (window->BeginCount > 1)
|
|
{
|
|
End();
|
|
}
|
|
else
|
|
{
|
|
ImVec2 sz = window->Size;
|
|
if (window->AutoFitChildAxises & (1 << ImGuiAxis_X))
|
|
sz.x = ImMax(4.0f, sz.x);
|
|
if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
|
|
sz.y = ImMax(4.0f, sz.y);
|
|
End();
|
|
|
|
ImGuiWindow* parent_window = g.CurrentWindow;
|
|
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
|
|
ItemSize(sz);
|
|
if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
|
|
{
|
|
ItemAdd(bb, window->ChildId);
|
|
RenderNavHighlight(bb, window->ChildId);
|
|
|
|
if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
|
|
RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
|
|
}
|
|
else
|
|
{
|
|
ItemAdd(bb, 0);
|
|
}
|
|
}
|
|
g.WithinEndChild = false;
|
|
g.LogLinePosY = -FLT_MAX;
|
|
}
|
|
|
|
bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
const ImGuiStyle& style = g.Style;
|
|
PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
|
|
PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
|
|
PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
|
|
PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
|
|
bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
|
|
PopStyleVar(3);
|
|
PopStyleColor();
|
|
return ret;
|
|
}
|
|
|
|
void ImGui::EndChildFrame()
|
|
{
|
|
EndChild();
|
|
}
|
|
|
|
static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
|
|
{
|
|
window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
|
|
window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags);
|
|
window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
|
|
}
|
|
|
|
ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
|
|
}
|
|
|
|
ImGuiWindow* ImGui::FindWindowByName(const char* name)
|
|
{
|
|
ImGuiID id = ImHashStr(name);
|
|
return FindWindowByID(id);
|
|
}
|
|
|
|
static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
|
|
{
|
|
window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));
|
|
if (settings->Size.x > 0 && settings->Size.y > 0)
|
|
window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
|
|
window->Collapsed = settings->Collapsed;
|
|
}
|
|
|
|
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
|
|
window->Flags = flags;
|
|
g.WindowsById.SetVoidPtr(window->ID, window);
|
|
|
|
window->Pos = ImVec2(60, 60);
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoSavedSettings))
|
|
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
|
|
{
|
|
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
|
|
ApplyWindowSettings(window, settings);
|
|
}
|
|
window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos;
|
|
|
|
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
|
|
{
|
|
window->AutoFitFramesX = window->AutoFitFramesY = 2;
|
|
window->AutoFitOnlyGrows = false;
|
|
}
|
|
else
|
|
{
|
|
if (window->Size.x <= 0.0f)
|
|
window->AutoFitFramesX = 2;
|
|
if (window->Size.y <= 0.0f)
|
|
window->AutoFitFramesY = 2;
|
|
window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
|
|
}
|
|
|
|
g.WindowsFocusOrder.push_back(window);
|
|
if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
|
|
g.Windows.push_front(window);
|
|
else
|
|
g.Windows.push_back(window);
|
|
return window;
|
|
}
|
|
|
|
static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
|
{
|
|
ImRect cr = g.NextWindowData.SizeConstraintRect;
|
|
new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
|
|
new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
|
|
if (g.NextWindowData.SizeCallback)
|
|
{
|
|
ImGuiSizeCallbackData data;
|
|
data.UserData = g.NextWindowData.SizeCallbackUserData;
|
|
data.Pos = window->Pos;
|
|
data.CurrentSize = window->SizeFull;
|
|
data.DesiredSize = new_size;
|
|
g.NextWindowData.SizeCallback(&data);
|
|
new_size = data.DesiredSize;
|
|
}
|
|
new_size.x = IM_FLOOR(new_size.x);
|
|
new_size.y = IM_FLOOR(new_size.y);
|
|
}
|
|
|
|
if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
|
|
{
|
|
ImGuiWindow* window_for_height = window;
|
|
new_size = ImMax(new_size, g.Style.WindowMinSize);
|
|
new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f));
|
|
}
|
|
return new_size;
|
|
}
|
|
|
|
static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal)
|
|
{
|
|
bool preserve_old_content_sizes = false;
|
|
if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
|
|
preserve_old_content_sizes = true;
|
|
else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
|
|
preserve_old_content_sizes = true;
|
|
if (preserve_old_content_sizes)
|
|
{
|
|
*content_size_current = window->ContentSize;
|
|
*content_size_ideal = window->ContentSizeIdeal;
|
|
return;
|
|
}
|
|
|
|
content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
|
|
content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
|
|
content_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);
|
|
content_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);
|
|
}
|
|
|
|
static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiStyle& style = g.Style;
|
|
ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
|
|
ImVec2 size_pad = window->WindowPadding * 2.0f;
|
|
ImVec2 size_desired = size_contents + size_pad + size_decorations;
|
|
if (window->Flags & ImGuiWindowFlags_Tooltip)
|
|
{
|
|
return size_desired;
|
|
}
|
|
else
|
|
{
|
|
const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
|
|
const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
|
|
ImVec2 size_min = style.WindowMinSize;
|
|
if (is_popup || is_menu)
|
|
size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
|
|
ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
|
|
|
|
ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
|
|
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
|
|
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
|
if (will_have_scrollbar_x)
|
|
size_auto_fit.y += style.ScrollbarSize;
|
|
if (will_have_scrollbar_y)
|
|
size_auto_fit.x += style.ScrollbarSize;
|
|
return size_auto_fit;
|
|
}
|
|
}
|
|
|
|
ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window)
|
|
{
|
|
ImVec2 size_contents_current;
|
|
ImVec2 size_contents_ideal;
|
|
CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal);
|
|
ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal);
|
|
ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
|
|
return size_final;
|
|
}
|
|
|
|
static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
|
|
{
|
|
if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
|
|
return ImGuiCol_PopupBg;
|
|
if (flags & ImGuiWindowFlags_ChildWindow)
|
|
return ImGuiCol_ChildBg;
|
|
return ImGuiCol_WindowBg;
|
|
}
|
|
|
|
static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
|
|
{
|
|
ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);
|
|
ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm);
|
|
ImVec2 size_expected = pos_max - pos_min;
|
|
ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
|
|
*out_pos = pos_min;
|
|
if (corner_norm.x == 0.0f)
|
|
out_pos->x -= (size_constrained.x - size_expected.x);
|
|
if (corner_norm.y == 0.0f)
|
|
out_pos->y -= (size_constrained.y - size_expected.y);
|
|
*out_size = size_constrained;
|
|
}
|
|
|
|
struct ImGuiResizeGripDef
|
|
{
|
|
ImVec2 CornerPosN;
|
|
ImVec2 InnerDir;
|
|
int AngleMin12, AngleMax12;
|
|
};
|
|
|
|
static const ImGuiResizeGripDef resize_grip_def[4] =
|
|
{
|
|
{ ImVec2(1, 1), ImVec2(-1, -1), 0, 3 },
|
|
{ ImVec2(0, 1), ImVec2(+1, -1), 3, 6 },
|
|
{ ImVec2(0, 0), ImVec2(+1, +1), 6, 9 },
|
|
{ ImVec2(1, 0), ImVec2(-1, +1), 9, 12 },
|
|
};
|
|
|
|
struct ImGuiResizeBorderDef
|
|
{
|
|
ImVec2 InnerDir;
|
|
ImVec2 CornerPosN1, CornerPosN2;
|
|
float OuterAngle;
|
|
};
|
|
|
|
static const ImGuiResizeBorderDef resize_border_def[4] =
|
|
{
|
|
{ ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f },
|
|
{ ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f },
|
|
{ ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f },
|
|
{ ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }
|
|
};
|
|
|
|
static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
|
|
{
|
|
ImRect rect = window->Rect();
|
|
if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
|
|
if (border_n == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }
|
|
if (border_n == 1) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }
|
|
if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }
|
|
if (border_n == 3) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }
|
|
IM_ASSERT(0);
|
|
return ImRect();
|
|
}
|
|
|
|
ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
|
|
{
|
|
IM_ASSERT(n >= 0 && n <= 7);
|
|
ImGuiID id = window->ID;
|
|
id = ImHashStr("#RESIZE", 0, id);
|
|
id = ImHashData(&n, sizeof(int), id);
|
|
return id;
|
|
}
|
|
|
|
static 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)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindowFlags flags = window->Flags;
|
|
|
|
if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
|
|
return false;
|
|
if (window->WasActive == false)
|
|
return false;
|
|
|
|
bool ret_auto_fit = false;
|
|
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
|
|
const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
|
|
const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
|
|
const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
|
|
|
|
ImVec2 pos_target(FLT_MAX, FLT_MAX);
|
|
ImVec2 size_target(FLT_MAX, FLT_MAX);
|
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
|
|
|
|
PushID("#RESIZE");
|
|
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
|
|
{
|
|
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
|
|
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
|
|
|
|
ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
|
|
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
|
|
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
|
|
bool hovered, held;
|
|
ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
|
|
if (hovered || held)
|
|
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
|
|
|
|
if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
|
|
{
|
|
size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
|
|
ret_auto_fit = true;
|
|
ClearActiveID();
|
|
}
|
|
else if (held)
|
|
{
|
|
ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN);
|
|
ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
|
|
ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
|
|
corner_target = ImClamp(corner_target, clamp_min, clamp_max);
|
|
CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
|
|
}
|
|
if (resize_grip_n == 0 || held || hovered)
|
|
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
|
|
}
|
|
for (int border_n = 0; border_n < resize_border_count; border_n++)
|
|
{
|
|
bool hovered, held;
|
|
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
|
|
ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
|
|
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
|
|
{
|
|
g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
|
|
if (held)
|
|
*border_held = border_n;
|
|
}
|
|
if (held)
|
|
{
|
|
ImVec2 border_target = window->Pos;
|
|
ImVec2 border_posn;
|
|
if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); }
|
|
if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); }
|
|
if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); }
|
|
if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); }
|
|
ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX);
|
|
ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX);
|
|
border_target = ImClamp(border_target, clamp_min, clamp_max);
|
|
CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
|
|
}
|
|
}
|
|
PopID();
|
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
|
|
|
|
if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
|
|
{
|
|
ImVec2 nav_resize_delta;
|
|
if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
|
|
nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
|
|
if (g.NavInputSource == ImGuiInputSource_NavGamepad)
|
|
nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
|
|
if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
|
|
{
|
|
const float NAV_RESIZE_SPEED = 600.0f;
|
|
nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
|
|
nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size);
|
|
g.NavWindowingToggleLayer = false;
|
|
g.NavDisableMouseHover = true;
|
|
resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
|
|
size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
|
|
}
|
|
}
|
|
|
|
if (size_target.x != FLT_MAX)
|
|
{
|
|
window->SizeFull = size_target;
|
|
MarkIniSettingsDirty(window);
|
|
}
|
|
if (pos_target.x != FLT_MAX)
|
|
{
|
|
window->Pos = ImFloor(pos_target);
|
|
MarkIniSettingsDirty(window);
|
|
}
|
|
|
|
window->Size = window->SizeFull;
|
|
return ret_auto_fit;
|
|
}
|
|
|
|
static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImVec2 size_for_clamping = window->Size;
|
|
if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
size_for_clamping.y = window->TitleBarHeight();
|
|
window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
|
|
}
|
|
|
|
static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
float rounding = window->WindowRounding;
|
|
float border_size = window->WindowBorderSize;
|
|
if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
|
|
window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
|
|
|
|
int border_held = window->ResizeBorderHeld;
|
|
if (border_held != -1)
|
|
{
|
|
const ImGuiResizeBorderDef& def = resize_border_def[border_held];
|
|
ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
|
|
window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
|
|
window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
|
|
window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size));
|
|
}
|
|
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
{
|
|
float y = window->Pos.y + window->TitleBarHeight() - 1;
|
|
window->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);
|
|
}
|
|
}
|
|
|
|
|
|
void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
|
|
{
|
|
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiStyle& style = g.Style;
|
|
ImGuiWindowFlags flags = window->Flags;
|
|
|
|
IM_ASSERT(window->BeginCount == 0);
|
|
window->SkipItems = false;
|
|
|
|
const float window_rounding = window->WindowRounding;
|
|
const float window_border_size = window->WindowBorderSize;
|
|
if (window->Collapsed)
|
|
{
|
|
float backup_border_size = style.FrameBorderSize;
|
|
g.Style.FrameBorderSize = window->WindowBorderSize;
|
|
ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
|
|
RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
|
|
g.Style.FrameBorderSize = backup_border_size;
|
|
}
|
|
else
|
|
{
|
|
if (!(flags & ImGuiWindowFlags_NoBackground))
|
|
{
|
|
ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
|
|
bool override_alpha = false;
|
|
float alpha = 1.0f;
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
|
|
{
|
|
alpha = g.NextWindowData.BgAlphaVal;
|
|
override_alpha = true;
|
|
}
|
|
if (override_alpha)
|
|
bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
|
|
window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
|
|
}
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoTitleBar))
|
|
{
|
|
ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
|
|
window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
|
|
}
|
|
|
|
if (flags & ImGuiWindowFlags_MenuBar)
|
|
{
|
|
ImRect menu_bar_rect = window->MenuBarRect();
|
|
menu_bar_rect.ClipWith(window->Rect());
|
|
window->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, ImDrawCornerFlags_Top);
|
|
|
|
if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
|
|
window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
|
|
}
|
|
|
|
if (window->ScrollbarX)
|
|
Scrollbar(ImGuiAxis_X);
|
|
if (window->ScrollbarY)
|
|
Scrollbar(ImGuiAxis_Y);
|
|
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoResize))
|
|
{
|
|
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
|
|
{
|
|
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
|
|
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
|
|
window->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)));
|
|
window->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)));
|
|
window->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);
|
|
window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
|
|
}
|
|
}
|
|
|
|
RenderWindowOuterBorders(window);
|
|
}
|
|
}
|
|
|
|
void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiStyle& style = g.Style;
|
|
ImGuiWindowFlags flags = window->Flags;
|
|
|
|
const bool has_close_button = (p_open != NULL);
|
|
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
|
|
|
|
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
|
|
window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
|
|
|
|
float pad_l = style.FramePadding.x;
|
|
float pad_r = style.FramePadding.x;
|
|
float button_sz = g.FontSize;
|
|
ImVec2 close_button_pos;
|
|
ImVec2 collapse_button_pos;
|
|
if (has_close_button)
|
|
{
|
|
pad_r += button_sz;
|
|
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
|
|
}
|
|
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
|
|
{
|
|
pad_r += button_sz;
|
|
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
|
|
}
|
|
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
|
|
{
|
|
collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
|
|
pad_l += button_sz;
|
|
}
|
|
|
|
if (has_collapse_button)
|
|
if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
|
|
window->WantCollapseToggle = true;
|
|
|
|
if (has_close_button)
|
|
if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
|
|
*p_open = false;
|
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
|
|
window->DC.ItemFlags = item_flags_backup;
|
|
|
|
const char* UNSAVED_DOCUMENT_MARKER = "*";
|
|
const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
|
|
const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
|
|
|
|
if (pad_l > style.FramePadding.x)
|
|
pad_l += g.Style.ItemInnerSpacing.x;
|
|
if (pad_r > style.FramePadding.x)
|
|
pad_r += g.Style.ItemInnerSpacing.x;
|
|
if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
|
|
{
|
|
float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f);
|
|
float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
|
|
pad_l = ImMax(pad_l, pad_extend * centerness);
|
|
pad_r = ImMax(pad_r, pad_extend * centerness);
|
|
}
|
|
|
|
pad_l += 10.0f;
|
|
|
|
ImRect 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);
|
|
ImRect 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);
|
|
RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
|
|
if (flags & ImGuiWindowFlags_UnsavedDocument)
|
|
{
|
|
ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
|
|
ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
|
|
RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
|
|
}
|
|
}
|
|
|
|
void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
|
|
{
|
|
window->ParentWindow = parent_window;
|
|
window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
|
|
if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
|
|
window->RootWindow = parent_window->RootWindow;
|
|
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
|
|
window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
|
|
while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
|
|
{
|
|
IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
|
|
window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
|
|
}
|
|
}
|
|
|
|
bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
const ImGuiStyle& style = g.Style;
|
|
IM_ASSERT(name != NULL && name[0] != '\0');
|
|
IM_ASSERT(g.WithinFrameScope);
|
|
IM_ASSERT(g.FrameCountEnded != g.FrameCount);
|
|
|
|
ImGuiWindow* window = FindWindowByName(name);
|
|
|
|
const bool window_just_created = (window == NULL);
|
|
if (window_just_created)
|
|
window = CreateNewWindow(name, flags);
|
|
|
|
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
|
|
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
|
|
|
if (flags & ImGuiWindowFlags_NavFlattened)
|
|
IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
|
|
|
|
const int current_frame = g.FrameCount;
|
|
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
|
|
window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
|
|
|
|
bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);
|
|
const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
{
|
|
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId);
|
|
window_just_activated_by_user |= (window != popup_ref.Window);
|
|
}
|
|
window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
|
|
if (window->Appearing)
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
|
|
|
|
if (first_begin_of_the_frame)
|
|
{
|
|
window->Flags = (ImGuiWindowFlags)flags;
|
|
window->LastFrameActive = current_frame;
|
|
window->LastTimeActive = (float)g.Time;
|
|
window->BeginOrderWithinParent = 0;
|
|
window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
|
|
}
|
|
else
|
|
{
|
|
flags = window->Flags;
|
|
}
|
|
|
|
ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
|
|
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
|
|
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
|
|
|
|
if (window->IDStack.Size == 0)
|
|
window->IDStack.push_back(window->ID);
|
|
|
|
g.CurrentWindowStack.push_back(window);
|
|
g.CurrentWindow = window;
|
|
window->DC.StackSizesOnBegin.SetToCurrentState();
|
|
g.CurrentWindow = NULL;
|
|
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
{
|
|
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
popup_ref.Window = window;
|
|
g.BeginPopupStack.push_back(popup_ref);
|
|
window->PopupId = popup_ref.PopupId;
|
|
}
|
|
|
|
if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
|
|
window->NavLastIds[0] = 0;
|
|
|
|
if (first_begin_of_the_frame)
|
|
UpdateWindowParentAndRootLinks(window, flags, parent_window);
|
|
|
|
bool window_pos_set_by_api = false;
|
|
bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
|
|
{
|
|
window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
|
|
if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
|
|
{
|
|
window->SetWindowPosVal = g.NextWindowData.PosVal;
|
|
window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
|
|
window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
|
|
}
|
|
else
|
|
{
|
|
SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
|
|
}
|
|
}
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
|
|
{
|
|
window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
|
|
window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
|
|
SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
|
|
}
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)
|
|
{
|
|
if (g.NextWindowData.ScrollVal.x >= 0.0f)
|
|
{
|
|
window->ScrollTarget.x = g.NextWindowData.ScrollVal.x;
|
|
window->ScrollTargetCenterRatio.x = 0.0f;
|
|
}
|
|
if (g.NextWindowData.ScrollVal.y >= 0.0f)
|
|
{
|
|
window->ScrollTarget.y = g.NextWindowData.ScrollVal.y;
|
|
window->ScrollTargetCenterRatio.y = 0.0f;
|
|
}
|
|
}
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
|
|
window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
|
|
else if (first_begin_of_the_frame)
|
|
window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
|
|
SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
|
|
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
|
|
FocusWindow(window);
|
|
if (window->Appearing)
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
|
|
|
|
if (first_begin_of_the_frame)
|
|
{
|
|
const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip);
|
|
window->Active = true;
|
|
window->HasCloseButton = (p_open != NULL);
|
|
window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
|
|
window->IDStack.resize(1);
|
|
window->DrawList->_ResetForNewFrame();
|
|
window->DC.CurrentTableIdx = -1;
|
|
|
|
if (window->MemoryCompacted)
|
|
GcAwakeTransientWindowBuffers(window);
|
|
|
|
bool window_title_visible_elsewhere = false;
|
|
if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)
|
|
window_title_visible_elsewhere = true;
|
|
if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
|
|
{
|
|
size_t buf_len = (size_t)window->NameBufLen;
|
|
window->Name = ImStrdupcpy(window->Name, &buf_len, name);
|
|
window->NameBufLen = (int)buf_len;
|
|
}
|
|
|
|
CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
|
|
if (window->HiddenFramesCanSkipItems > 0)
|
|
window->HiddenFramesCanSkipItems--;
|
|
if (window->HiddenFramesCannotSkipItems > 0)
|
|
window->HiddenFramesCannotSkipItems--;
|
|
if (window->HiddenFramesForRenderOnly > 0)
|
|
window->HiddenFramesForRenderOnly--;
|
|
|
|
if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
|
|
window->HiddenFramesCannotSkipItems = 1;
|
|
|
|
if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
|
|
{
|
|
window->HiddenFramesCannotSkipItems = 1;
|
|
if (flags & ImGuiWindowFlags_AlwaysAutoResize)
|
|
{
|
|
if (!window_size_x_set_by_api)
|
|
window->Size.x = window->SizeFull.x = 0.f;
|
|
if (!window_size_y_set_by_api)
|
|
window->Size.y = window->SizeFull.y = 0.f;
|
|
window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f);
|
|
}
|
|
}
|
|
|
|
SetCurrentWindow(window);
|
|
|
|
if (flags & ImGuiWindowFlags_ChildWindow)
|
|
window->WindowBorderSize = style.ChildBorderSize;
|
|
else
|
|
window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
|
|
window->WindowPadding = style.WindowPadding;
|
|
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
|
|
window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
|
|
|
|
window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
|
|
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
|
|
{
|
|
ImRect title_bar_rect = window->TitleBarRect();
|
|
if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
|
|
window->WantCollapseToggle = true;
|
|
if (window->WantCollapseToggle)
|
|
{
|
|
window->Collapsed = !window->Collapsed;
|
|
MarkIniSettingsDirty(window);
|
|
FocusWindow(window);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
window->Collapsed = false;
|
|
}
|
|
window->WantCollapseToggle = false;
|
|
|
|
const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal);
|
|
bool use_current_size_for_scrollbar_x = window_just_created;
|
|
bool use_current_size_for_scrollbar_y = window_just_created;
|
|
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
|
|
{
|
|
if (!window_size_x_set_by_api)
|
|
{
|
|
window->SizeFull.x = size_auto_fit.x;
|
|
use_current_size_for_scrollbar_x = true;
|
|
}
|
|
if (!window_size_y_set_by_api)
|
|
{
|
|
window->SizeFull.y = size_auto_fit.y;
|
|
use_current_size_for_scrollbar_y = true;
|
|
}
|
|
}
|
|
else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
|
|
{
|
|
if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
|
|
{
|
|
window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
|
|
use_current_size_for_scrollbar_x = true;
|
|
}
|
|
if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
|
|
{
|
|
window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
|
|
use_current_size_for_scrollbar_y = true;
|
|
}
|
|
if (!window->Collapsed)
|
|
MarkIniSettingsDirty(window);
|
|
}
|
|
|
|
window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
|
|
window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
|
|
|
|
const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
|
|
|
|
if (window_just_activated_by_user)
|
|
{
|
|
window->AutoPosLastDirection = ImGuiDir_None;
|
|
if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api)
|
|
window->Pos = g.BeginPopupStack.back().OpenPopupPos;
|
|
}
|
|
|
|
if (flags & ImGuiWindowFlags_ChildWindow)
|
|
{
|
|
IM_ASSERT(parent_window && parent_window->Active);
|
|
window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
|
|
parent_window->DC.ChildWindows.push_back(window);
|
|
if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
|
|
window->Pos = parent_window->DC.CursorPos;
|
|
}
|
|
|
|
const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
|
|
if (window_pos_with_pivot)
|
|
SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0);
|
|
else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
|
|
window->Pos = FindBestWindowPosForPopup(window);
|
|
else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
|
|
window->Pos = FindBestWindowPosForPopup(window);
|
|
else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
|
|
window->Pos = FindBestWindowPosForPopup(window);
|
|
|
|
ImRect viewport_rect(GetViewportRect());
|
|
|
|
ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
|
|
ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding);
|
|
|
|
if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
|
|
if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)
|
|
ClampWindowRect(window, visibility_rect);
|
|
window->Pos = ImFloor(window->Pos);
|
|
|
|
window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
|
|
|
|
bool want_focus = false;
|
|
if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
|
|
{
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
want_focus = true;
|
|
else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
|
|
want_focus = true;
|
|
}
|
|
|
|
int border_held = -1;
|
|
ImU32 resize_grip_col[4] = {};
|
|
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1;
|
|
const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
|
|
if (!window->Collapsed)
|
|
if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
|
|
use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
|
|
window->ResizeBorderHeld = (signed char)border_held;
|
|
|
|
if (!window->Collapsed)
|
|
{
|
|
ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
|
|
ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
|
|
ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
|
|
float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
|
|
float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
|
|
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
|
|
window->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));
|
|
if (window->ScrollbarX && !window->ScrollbarY)
|
|
window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
|
|
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
|
|
}
|
|
|
|
const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
|
|
const ImRect outer_rect = window->Rect();
|
|
const ImRect title_bar_rect = window->TitleBarRect();
|
|
window->OuterRectClipped = outer_rect;
|
|
window->OuterRectClipped.ClipWith(host_rect);
|
|
|
|
window->InnerRect.Min.x = window->Pos.x;
|
|
window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
|
|
window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
|
|
window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
|
|
|
|
float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
|
|
window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
|
|
window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
|
|
window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
|
|
window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
|
|
window->InnerClipRect.ClipWithFull(host_rect);
|
|
|
|
if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
|
|
window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
|
|
else
|
|
window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
|
|
|
|
window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
|
|
window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
|
|
|
|
window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
|
|
window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
|
|
|
|
IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
|
|
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
|
|
PushClipRect(host_rect.Min, host_rect.Max, false);
|
|
|
|
const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
|
|
const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
|
|
if (dim_bg_for_modal || dim_bg_for_window_list)
|
|
{
|
|
const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
|
|
window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
|
|
}
|
|
|
|
if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
|
|
{
|
|
ImRect bb = window->Rect();
|
|
bb.Expand(g.FontSize);
|
|
if (!bb.Contains(viewport_rect))
|
|
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
|
|
}
|
|
|
|
{
|
|
bool render_decorations_in_parent = false;
|
|
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
|
|
if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
|
|
render_decorations_in_parent = true;
|
|
if (render_decorations_in_parent)
|
|
window->DrawList = parent_window->DrawList;
|
|
|
|
const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
|
|
const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
|
|
RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
|
|
|
|
if (render_decorations_in_parent)
|
|
window->DrawList = &window->DrawListInst;
|
|
}
|
|
|
|
if (g.NavWindowingTargetAnim == window)
|
|
{
|
|
float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
|
|
ImRect bb = window->Rect();
|
|
bb.Expand(g.FontSize);
|
|
if (bb.Contains(viewport_rect))
|
|
{
|
|
bb.Expand(-g.FontSize - 1.0f);
|
|
rounding = window->WindowRounding;
|
|
}
|
|
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
|
|
}
|
|
|
|
const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
|
|
const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
|
|
const 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->ScrollbarSizes.x));
|
|
const 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 - decoration_up_height - window->ScrollbarSizes.y));
|
|
window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
|
|
window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
|
|
window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
|
|
window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
|
|
window->ParentWorkRect = window->WorkRect;
|
|
|
|
window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
|
|
window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
|
|
window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
|
|
window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
|
|
|
|
window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
|
|
window->DC.GroupOffset.x = 0.0f;
|
|
window->DC.ColumnsOffset.x = 0.0f;
|
|
window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
|
|
window->DC.CursorPos = window->DC.CursorStartPos;
|
|
window->DC.CursorPosPrevLine = window->DC.CursorPos;
|
|
window->DC.CursorMaxPos = window->DC.CursorStartPos;
|
|
window->DC.IdealMaxPos = window->DC.CursorStartPos;
|
|
window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
|
|
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
|
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
|
|
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
|
|
window->DC.NavLayerActiveMaskNext = 0x00;
|
|
window->DC.NavHideHighlightOneFrame = false;
|
|
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
|
|
|
|
window->DC.MenuBarAppending = false;
|
|
window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
|
|
window->DC.TreeDepth = 0;
|
|
window->DC.TreeJumpToParentOnPopMask = 0x00;
|
|
window->DC.ChildWindows.resize(0);
|
|
window->DC.StateStorage = &window->StateStorage;
|
|
window->DC.CurrentColumns = NULL;
|
|
window->DC.LayoutType = ImGuiLayoutType_Vertical;
|
|
window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
|
|
window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1;
|
|
|
|
window->DC.ItemWidth = window->ItemWidthDefault;
|
|
window->DC.TextWrapPos = -1.0f;
|
|
window->DC.ItemWidthStack.resize(0);
|
|
window->DC.TextWrapPosStack.resize(0);
|
|
|
|
if (window->AutoFitFramesX > 0)
|
|
window->AutoFitFramesX--;
|
|
if (window->AutoFitFramesY > 0)
|
|
window->AutoFitFramesY--;
|
|
|
|
if (want_focus)
|
|
{
|
|
FocusWindow(window);
|
|
NavInitWindow(window, false);
|
|
}
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoTitleBar))
|
|
RenderWindowTitleBarContents(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);
|
|
|
|
window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
|
|
|
|
SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
SetCurrentWindow(window);
|
|
}
|
|
|
|
window->DC.ItemFlags = g.ItemFlagsStack.back();
|
|
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0;
|
|
|
|
PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
|
|
|
|
window->WriteAccessed = false;
|
|
window->BeginCount++;
|
|
g.NextWindowData.ClearFlags();
|
|
|
|
if (first_begin_of_the_frame)
|
|
{
|
|
if (flags & ImGuiWindowFlags_ChildWindow)
|
|
{
|
|
IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
|
|
if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
|
|
if (!g.LogEnabled)
|
|
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
|
|
window->HiddenFramesCanSkipItems = 1;
|
|
|
|
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
|
|
window->HiddenFramesCanSkipItems = 1;
|
|
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
|
|
window->HiddenFramesCannotSkipItems = 1;
|
|
}
|
|
|
|
if (style.Alpha <= 0.0f)
|
|
window->HiddenFramesCanSkipItems = 1;
|
|
|
|
window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0);
|
|
|
|
bool skip_items = false;
|
|
if (window->Collapsed || !window->Active || window->Hidden)
|
|
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
|
|
skip_items = true;
|
|
window->SkipItems = skip_items;
|
|
}
|
|
|
|
return !window->SkipItems;
|
|
}
|
|
|
|
void ImGui::End()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
|
|
{
|
|
IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
|
|
return;
|
|
}
|
|
IM_ASSERT(g.CurrentWindowStack.Size > 0);
|
|
|
|
if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
|
|
|
|
if (window->DC.CurrentColumns)
|
|
EndColumns();
|
|
PopClipRect();
|
|
|
|
if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
LogFinish();
|
|
|
|
g.CurrentWindowStack.pop_back();
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
g.BeginPopupStack.pop_back();
|
|
window->DC.StackSizesOnBegin.CompareWithCurrentState();
|
|
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
|
|
}
|
|
|
|
void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.WindowsFocusOrder.back() == window)
|
|
return;
|
|
for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--)
|
|
if (g.WindowsFocusOrder[i] == window)
|
|
{
|
|
memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
|
|
g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* current_front_window = g.Windows.back();
|
|
if (current_front_window == window || current_front_window->RootWindow == window)
|
|
return;
|
|
for (int i = g.Windows.Size - 2; i >= 0; i--)
|
|
if (g.Windows[i] == window)
|
|
{
|
|
memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
|
|
g.Windows[g.Windows.Size - 1] = window;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.Windows[0] == window)
|
|
return;
|
|
for (int i = 0; i < g.Windows.Size; i++)
|
|
if (g.Windows[i] == window)
|
|
{
|
|
memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
|
|
g.Windows[0] = window;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ImGui::FocusWindow(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (g.NavWindow != window)
|
|
{
|
|
g.NavWindow = window;
|
|
if (window && g.NavDisableMouseHover)
|
|
g.NavMousePosDirty = true;
|
|
g.NavInitRequest = false;
|
|
g.NavId = window ? window->NavLastIds[0] : 0;
|
|
g.NavFocusScopeId = 0;
|
|
g.NavIdIsAlive = false;
|
|
g.NavLayer = ImGuiNavLayer_Main;
|
|
}
|
|
|
|
ClosePopupsOverWindow(window, false);
|
|
|
|
IM_ASSERT(window == NULL || window->RootWindow != NULL);
|
|
ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL;
|
|
ImGuiWindow* display_front_window = window ? window->RootWindow : NULL;
|
|
|
|
if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
|
|
if (!g.ActiveIdNoClearOnFocusLoss)
|
|
ClearActiveID();
|
|
|
|
if (!window)
|
|
return;
|
|
|
|
BringWindowToFocusFront(focus_front_window);
|
|
if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
|
|
BringWindowToDisplayFront(display_front_window);
|
|
}
|
|
|
|
void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
int start_idx = g.WindowsFocusOrder.Size - 1;
|
|
if (under_this_window != NULL)
|
|
{
|
|
int under_this_window_idx = FindWindowFocusIndex(under_this_window);
|
|
if (under_this_window_idx != -1)
|
|
start_idx = under_this_window_idx - 1;
|
|
}
|
|
for (int i = start_idx; i >= 0; i--)
|
|
{
|
|
ImGuiWindow* window = g.WindowsFocusOrder[i];
|
|
if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
|
|
{
|
|
ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
|
|
FocusWindow(focus_window);
|
|
return;
|
|
}
|
|
}
|
|
FocusWindow(NULL);
|
|
}
|
|
|
|
void ImGui::SetCurrentFont(ImFont* font)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(font && font->IsLoaded());
|
|
IM_ASSERT(font->Scale > 0.0f);
|
|
g.Font = font;
|
|
g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
|
|
g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
|
|
|
|
ImFontAtlas* atlas = g.Font->ContainerAtlas;
|
|
g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
|
|
g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
|
|
g.DrawListSharedData.Font = g.Font;
|
|
g.DrawListSharedData.FontSize = g.FontSize;
|
|
}
|
|
|
|
void ImGui::PushFont(ImFont* font)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!font)
|
|
font = GetDefaultFont();
|
|
SetCurrentFont(font);
|
|
g.FontStack.push_back(font);
|
|
g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
|
|
}
|
|
|
|
void ImGui::PopFont()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.CurrentWindow->DrawList->PopTextureID();
|
|
g.FontStack.pop_back();
|
|
SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
|
|
}
|
|
|
|
void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiItemFlags item_flags = window->DC.ItemFlags;
|
|
IM_ASSERT(item_flags == g.ItemFlagsStack.back());
|
|
if (enabled)
|
|
item_flags |= option;
|
|
else
|
|
item_flags &= ~option;
|
|
window->DC.ItemFlags = item_flags;
|
|
g.ItemFlagsStack.push_back(item_flags);
|
|
}
|
|
|
|
void ImGui::PopItemFlag()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(g.ItemFlagsStack.Size > 1);
|
|
g.ItemFlagsStack.pop_back();
|
|
window->DC.ItemFlags = g.ItemFlagsStack.back();
|
|
}
|
|
|
|
void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
|
|
{
|
|
PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
|
|
}
|
|
|
|
void ImGui::PopAllowKeyboardFocus()
|
|
{
|
|
PopItemFlag();
|
|
}
|
|
|
|
void ImGui::PushButtonRepeat(bool repeat)
|
|
{
|
|
PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
|
|
}
|
|
|
|
void ImGui::PopButtonRepeat()
|
|
{
|
|
PopItemFlag();
|
|
}
|
|
|
|
void ImGui::PushTextWrapPos(float wrap_pos_x)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);
|
|
window->DC.TextWrapPos = wrap_pos_x;
|
|
}
|
|
|
|
void ImGui::PopTextWrapPos()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
|
|
window->DC.TextWrapPosStack.pop_back();
|
|
}
|
|
|
|
bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
|
|
{
|
|
if (window->RootWindow == potential_parent)
|
|
return true;
|
|
while (window != NULL)
|
|
{
|
|
if (window == potential_parent)
|
|
return true;
|
|
window = window->ParentWindow;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (int i = g.Windows.Size - 1; i >= 0; i--)
|
|
{
|
|
ImGuiWindow* candidate_window = g.Windows[i];
|
|
if (candidate_window == potential_above)
|
|
return true;
|
|
if (candidate_window == potential_below)
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
|
|
{
|
|
IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (flags & ImGuiHoveredFlags_AnyWindow)
|
|
{
|
|
if (g.HoveredWindow == NULL)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
|
|
{
|
|
case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
|
|
if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
|
|
return false;
|
|
break;
|
|
case ImGuiHoveredFlags_RootWindow:
|
|
if (g.HoveredWindow != g.CurrentWindow->RootWindow)
|
|
return false;
|
|
break;
|
|
case ImGuiHoveredFlags_ChildWindows:
|
|
if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
|
|
return false;
|
|
break;
|
|
default:
|
|
if (g.HoveredWindow != g.CurrentWindow)
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!IsWindowContentHoverable(g.HoveredWindow, flags))
|
|
return false;
|
|
if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
|
|
if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (flags & ImGuiFocusedFlags_AnyWindow)
|
|
return g.NavWindow != NULL;
|
|
|
|
IM_ASSERT(g.CurrentWindow);
|
|
switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
|
|
{
|
|
case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
|
|
return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
|
|
case ImGuiFocusedFlags_RootWindow:
|
|
return g.NavWindow == g.CurrentWindow->RootWindow;
|
|
case ImGuiFocusedFlags_ChildWindows:
|
|
return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
|
|
default:
|
|
return g.NavWindow == g.CurrentWindow;
|
|
}
|
|
}
|
|
|
|
bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
|
|
{
|
|
return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
|
|
}
|
|
|
|
float ImGui::GetWindowWidth()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->Size.x;
|
|
}
|
|
|
|
float ImGui::GetWindowHeight()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->Size.y;
|
|
}
|
|
|
|
ImVec2 ImGui::GetWindowPos()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
return window->Pos;
|
|
}
|
|
|
|
void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
|
|
{
|
|
if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
|
|
return;
|
|
|
|
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond));
|
|
window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
|
|
window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
|
|
|
|
const ImVec2 old_pos = window->Pos;
|
|
window->Pos = ImFloor(pos);
|
|
ImVec2 offset = window->Pos - old_pos;
|
|
window->DC.CursorPos += offset;
|
|
window->DC.CursorMaxPos += offset;
|
|
window->DC.IdealMaxPos += offset;
|
|
window->DC.CursorStartPos += offset;
|
|
}
|
|
|
|
void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
SetWindowPos(window, pos, cond);
|
|
}
|
|
|
|
void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
|
|
{
|
|
if (ImGuiWindow* window = FindWindowByName(name))
|
|
SetWindowPos(window, pos, cond);
|
|
}
|
|
|
|
ImVec2 ImGui::GetWindowSize()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->Size;
|
|
}
|
|
|
|
void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
|
|
{
|
|
if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
|
|
return;
|
|
|
|
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond));
|
|
window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
|
|
|
|
if (size.x > 0.0f)
|
|
{
|
|
window->AutoFitFramesX = 0;
|
|
window->SizeFull.x = IM_FLOOR(size.x);
|
|
}
|
|
else
|
|
{
|
|
window->AutoFitFramesX = 2;
|
|
window->AutoFitOnlyGrows = false;
|
|
}
|
|
if (size.y > 0.0f)
|
|
{
|
|
window->AutoFitFramesY = 0;
|
|
window->SizeFull.y = IM_FLOOR(size.y);
|
|
}
|
|
else
|
|
{
|
|
window->AutoFitFramesY = 2;
|
|
window->AutoFitOnlyGrows = false;
|
|
}
|
|
}
|
|
|
|
void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
|
|
{
|
|
SetWindowSize(GImGui->CurrentWindow, size, cond);
|
|
}
|
|
|
|
void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
|
|
{
|
|
if (ImGuiWindow* window = FindWindowByName(name))
|
|
SetWindowSize(window, size, cond);
|
|
}
|
|
|
|
void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
|
|
{
|
|
if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
|
|
return;
|
|
window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
|
|
|
|
window->Collapsed = collapsed;
|
|
}
|
|
|
|
void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
|
|
{
|
|
IM_ASSERT(window->HitTestHoleSize.x == 0);
|
|
window->HitTestHoleSize = ImVec2ih(size);
|
|
window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
|
|
}
|
|
|
|
void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
|
|
{
|
|
SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
|
|
}
|
|
|
|
bool ImGui::IsWindowCollapsed()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->Collapsed;
|
|
}
|
|
|
|
bool ImGui::IsWindowAppearing()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->Appearing;
|
|
}
|
|
|
|
void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
|
|
{
|
|
if (ImGuiWindow* window = FindWindowByName(name))
|
|
SetWindowCollapsed(window, collapsed, cond);
|
|
}
|
|
|
|
void ImGui::SetWindowFocus()
|
|
{
|
|
FocusWindow(GImGui->CurrentWindow);
|
|
}
|
|
|
|
void ImGui::SetWindowFocus(const char* name)
|
|
{
|
|
if (name)
|
|
{
|
|
if (ImGuiWindow* window = FindWindowByName(name))
|
|
FocusWindow(window);
|
|
}
|
|
else
|
|
{
|
|
FocusWindow(NULL);
|
|
}
|
|
}
|
|
|
|
void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond));
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
|
|
g.NextWindowData.PosVal = pos;
|
|
g.NextWindowData.PosPivotVal = pivot;
|
|
g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
|
|
}
|
|
|
|
void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond));
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
|
|
g.NextWindowData.SizeVal = size;
|
|
g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
|
|
}
|
|
|
|
void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
|
|
g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
|
|
g.NextWindowData.SizeCallback = custom_callback;
|
|
g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
|
|
}
|
|
|
|
void ImGui::SetNextWindowContentSize(const ImVec2& size)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
|
|
g.NextWindowData.ContentSizeVal = ImFloor(size);
|
|
}
|
|
|
|
void ImGui::SetNextWindowScroll(const ImVec2& scroll)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll;
|
|
g.NextWindowData.ScrollVal = scroll;
|
|
}
|
|
|
|
void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond));
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
|
|
g.NextWindowData.CollapsedVal = collapsed;
|
|
g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
|
|
}
|
|
|
|
void ImGui::SetNextWindowFocus()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
|
|
}
|
|
|
|
void ImGui::SetNextWindowBgAlpha(float alpha)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
|
|
g.NextWindowData.BgAlphaVal = alpha;
|
|
}
|
|
|
|
ImDrawList* ImGui::GetWindowDrawList()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
return window->DrawList;
|
|
}
|
|
|
|
ImFont* ImGui::GetFont()
|
|
{
|
|
return GImGui->Font;
|
|
}
|
|
|
|
float ImGui::GetFontSize()
|
|
{
|
|
return GImGui->FontSize;
|
|
}
|
|
|
|
ImVec2 ImGui::GetFontTexUvWhitePixel()
|
|
{
|
|
return GImGui->DrawListSharedData.TexUvWhitePixel;
|
|
}
|
|
|
|
void ImGui::SetWindowFontScale(float scale)
|
|
{
|
|
IM_ASSERT(scale > 0.0f);
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->FontWindowScale = scale;
|
|
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
|
|
}
|
|
|
|
void ImGui::ActivateItem(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NavNextActivateId = id;
|
|
}
|
|
|
|
void ImGui::PushFocusScope(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent);
|
|
window->DC.NavFocusScopeIdCurrent = id;
|
|
}
|
|
|
|
void ImGui::PopFocusScope()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(g.FocusScopeStack.Size > 0);
|
|
window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back();
|
|
g.FocusScopeStack.pop_back();
|
|
}
|
|
|
|
void ImGui::SetKeyboardFocusHere(int offset)
|
|
{
|
|
IM_ASSERT(offset >= -1);
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
g.FocusRequestNextWindow = window;
|
|
g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset;
|
|
g.FocusRequestNextCounterTabStop = INT_MAX;
|
|
}
|
|
|
|
void ImGui::SetItemDefaultFocus()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (!window->Appearing)
|
|
return;
|
|
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
|
|
{
|
|
g.NavInitRequest = false;
|
|
g.NavInitResultId = g.NavWindow->DC.LastItemId;
|
|
g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
|
|
NavUpdateAnyRequestFlag();
|
|
if (!IsItemVisible())
|
|
SetScrollHereY();
|
|
}
|
|
}
|
|
|
|
void ImGui::SetStateStorage(ImGuiStorage* tree)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
window->DC.StateStorage = tree ? tree : &window->StateStorage;
|
|
}
|
|
|
|
ImGuiStorage* ImGui::GetStateStorage()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->DC.StateStorage;
|
|
}
|
|
|
|
void ImGui::PushID(const char* str_id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiID id = window->GetIDNoKeepAlive(str_id);
|
|
window->IDStack.push_back(id);
|
|
}
|
|
|
|
void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end);
|
|
window->IDStack.push_back(id);
|
|
}
|
|
|
|
void ImGui::PushID(const void* ptr_id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiID id = window->GetIDNoKeepAlive(ptr_id);
|
|
window->IDStack.push_back(id);
|
|
}
|
|
|
|
void ImGui::PushID(int int_id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiID id = window->GetIDNoKeepAlive(int_id);
|
|
window->IDStack.push_back(id);
|
|
}
|
|
|
|
void ImGui::PushOverrideID(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
window->IDStack.push_back(id);
|
|
}
|
|
|
|
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
|
|
{
|
|
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
|
ImGui::KeepAliveID(id);
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
|
#endif
|
|
return id;
|
|
}
|
|
|
|
void ImGui::PopID()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
IM_ASSERT(window->IDStack.Size > 1);
|
|
window->IDStack.pop_back();
|
|
}
|
|
|
|
ImGuiID ImGui::GetID(const char* str_id)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->GetID(str_id);
|
|
}
|
|
|
|
ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->GetID(str_id_begin, str_id_end);
|
|
}
|
|
|
|
ImGuiID ImGui::GetID(const void* ptr_id)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->GetID(ptr_id);
|
|
}
|
|
|
|
bool ImGui::IsRectVisible(const ImVec2& size)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
|
|
}
|
|
|
|
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
|
|
}
|
|
|
|
|
|
bool 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)
|
|
{
|
|
bool error = false;
|
|
if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
|
|
if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
|
|
if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
|
|
if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
|
|
if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
|
|
if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
|
|
if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
|
|
return !error;
|
|
}
|
|
|
|
static void ImGui::ErrorCheckNewFrameSanityChecks()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (true) IM_ASSERT(1); else IM_ASSERT(0);
|
|
|
|
IM_ASSERT(g.Initialized);
|
|
IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!");
|
|
IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
|
|
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!");
|
|
IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
|
|
IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
|
|
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
|
|
IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f && "Invalid style setting!");
|
|
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!");
|
|
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
|
|
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
|
|
for (int n = 0; n < ImGuiKey_COUNT; n++)
|
|
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
|
|
|
|
if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
|
|
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
|
|
|
|
if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
|
|
g.IO.ConfigWindowsResizeFromEdges = false;
|
|
}
|
|
|
|
static void ImGui::ErrorCheckEndFrameSanityChecks()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags();
|
|
IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
|
|
IM_UNUSED(key_mod_flags);
|
|
|
|
if (g.CurrentWindowStack.Size != 1)
|
|
{
|
|
if (g.CurrentWindowStack.Size > 1)
|
|
{
|
|
IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
|
|
while (g.CurrentWindowStack.Size > 1)
|
|
End();
|
|
}
|
|
else
|
|
{
|
|
IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
|
|
}
|
|
}
|
|
|
|
IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!");
|
|
}
|
|
|
|
void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
while (g.CurrentWindowStack.Size > 0)
|
|
{
|
|
#ifdef IMGUI_HAS_TABLE
|
|
while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
|
|
EndTable();
|
|
}
|
|
#endif
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(window != NULL);
|
|
while (g.CurrentTabBar != NULL)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name);
|
|
EndTabBar();
|
|
}
|
|
while (window->DC.TreeDepth > 0)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name);
|
|
TreePop();
|
|
}
|
|
while (g.GroupStack.Size > window->DC.StackSizesOnBegin.SizeOfGroupStack)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name);
|
|
EndGroup();
|
|
}
|
|
while (window->IDStack.Size > 1)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name);
|
|
PopID();
|
|
}
|
|
while (g.ColorStack.Size > window->DC.StackSizesOnBegin.SizeOfColorStack)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col));
|
|
PopStyleColor();
|
|
}
|
|
while (g.StyleVarStack.Size > window->DC.StackSizesOnBegin.SizeOfStyleVarStack)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
|
|
PopStyleVar();
|
|
}
|
|
while (g.FocusScopeStack.Size > window->DC.StackSizesOnBegin.SizeOfFocusScopeStack)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
|
|
PopFocusScope();
|
|
}
|
|
if (g.CurrentWindowStack.Size == 1)
|
|
{
|
|
IM_ASSERT(g.CurrentWindow->IsFallbackWindow);
|
|
break;
|
|
}
|
|
IM_ASSERT(window == g.CurrentWindow);
|
|
if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
|
|
EndChild();
|
|
}
|
|
else
|
|
{
|
|
if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name);
|
|
End();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImGuiStackSizes::SetToCurrentState()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
SizeOfIDStack = (short)window->IDStack.Size;
|
|
SizeOfColorStack = (short)g.ColorStack.Size;
|
|
SizeOfStyleVarStack = (short)g.StyleVarStack.Size;
|
|
SizeOfFontStack = (short)g.FontStack.Size;
|
|
SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;
|
|
SizeOfGroupStack = (short)g.GroupStack.Size;
|
|
SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;
|
|
}
|
|
|
|
void ImGuiStackSizes::CompareWithCurrentState()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_UNUSED(window);
|
|
|
|
IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!");
|
|
|
|
IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!");
|
|
IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!");
|
|
IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!");
|
|
IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!");
|
|
IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!");
|
|
IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!");
|
|
}
|
|
|
|
|
|
void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (window->SkipItems)
|
|
return;
|
|
|
|
const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
|
|
const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
|
|
|
|
window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
|
|
window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
|
window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
|
|
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
|
|
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
|
|
window->DC.PrevLineSize.y = line_height;
|
|
window->DC.CurrLineSize.y = 0.0f;
|
|
window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
|
|
window->DC.CurrLineTextBaseOffset = 0.0f;
|
|
|
|
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
|
|
SameLine();
|
|
}
|
|
|
|
void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
|
|
{
|
|
ItemSize(bb.GetSize(), text_baseline_y);
|
|
}
|
|
|
|
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
if (id != 0)
|
|
{
|
|
window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
|
|
if (g.NavId == id || g.NavAnyRequest)
|
|
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
|
|
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
|
|
NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
|
|
|
|
#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
|
if (id == g.DebugItemPickerBreakId)
|
|
{
|
|
IM_DEBUG_BREAK();
|
|
g.DebugItemPickerBreakId = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
window->DC.LastItemId = id;
|
|
window->DC.LastItemRect = bb;
|
|
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
|
|
g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
if (id != 0)
|
|
IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id);
|
|
#endif
|
|
|
|
const bool is_clipped = IsClippedEx(bb, id, false);
|
|
if (is_clipped)
|
|
return false;
|
|
if (IsMouseHoveringRect(bb.Min, bb.Max))
|
|
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
|
|
return true;
|
|
}
|
|
|
|
void ImGui::SameLine(float offset_from_start_x, float spacing_w)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
if (window->SkipItems)
|
|
return;
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
if (offset_from_start_x != 0.0f)
|
|
{
|
|
if (spacing_w < 0.0f) spacing_w = 0.0f;
|
|
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
|
|
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
|
|
}
|
|
else
|
|
{
|
|
if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
|
|
window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
|
|
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
|
|
}
|
|
window->DC.CurrLineSize = window->DC.PrevLineSize;
|
|
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
|
|
}
|
|
|
|
ImVec2 ImGui::GetCursorScreenPos()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.CursorPos;
|
|
}
|
|
|
|
void ImGui::SetCursorScreenPos(const ImVec2& pos)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.CursorPos = pos;
|
|
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
}
|
|
|
|
ImVec2 ImGui::GetCursorPos()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.CursorPos - window->Pos + window->Scroll;
|
|
}
|
|
|
|
float ImGui::GetCursorPosX()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
|
|
}
|
|
|
|
float ImGui::GetCursorPosY()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
|
|
}
|
|
|
|
void ImGui::SetCursorPos(const ImVec2& local_pos)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
|
|
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
}
|
|
|
|
void ImGui::SetCursorPosX(float x)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
|
|
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
|
|
}
|
|
|
|
void ImGui::SetCursorPosY(float y)
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
|
|
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
|
|
}
|
|
|
|
ImVec2 ImGui::GetCursorStartPos()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
return window->DC.CursorStartPos - window->Pos;
|
|
}
|
|
|
|
void ImGui::Indent(float indent_w)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
|
|
window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
|
|
}
|
|
|
|
void ImGui::Unindent(float indent_w)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
|
|
window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
|
|
}
|
|
|
|
void ImGui::SetNextItemWidth(float item_width)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
|
|
g.NextItemData.Width = item_width;
|
|
}
|
|
|
|
void ImGui::PushItemWidth(float item_width)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
|
|
window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
|
|
g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
}
|
|
|
|
void ImGui::PushMultiItemsWidths(int components, float w_full)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
const ImGuiStyle& style = g.Style;
|
|
const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
|
|
const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
|
|
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
|
|
window->DC.ItemWidthStack.push_back(w_item_last);
|
|
for (int i = 0; i < components - 2; i++)
|
|
window->DC.ItemWidthStack.push_back(w_item_one);
|
|
window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one;
|
|
g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
}
|
|
|
|
void ImGui::PopItemWidth()
|
|
{
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
|
|
window->DC.ItemWidthStack.pop_back();
|
|
}
|
|
|
|
float ImGui::CalcItemWidth()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
float w;
|
|
if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
|
|
w = g.NextItemData.Width;
|
|
else
|
|
w = window->DC.ItemWidth;
|
|
if (w < 0.0f)
|
|
{
|
|
float region_max_x = GetContentRegionMaxAbs().x;
|
|
w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
|
|
}
|
|
w = IM_FLOOR(w);
|
|
return w;
|
|
}
|
|
|
|
ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
|
ImVec2 region_max;
|
|
if (size.x < 0.0f || size.y < 0.0f)
|
|
region_max = GetContentRegionMaxAbs();
|
|
|
|
if (size.x == 0.0f)
|
|
size.x = default_w;
|
|
else if (size.x < 0.0f)
|
|
size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
|
|
|
|
if (size.y == 0.0f)
|
|
size.y = default_h;
|
|
else if (size.y < 0.0f)
|
|
size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
|
|
|
|
return size;
|
|
}
|
|
|
|
float ImGui::GetTextLineHeight()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.FontSize;
|
|
}
|
|
|
|
float ImGui::GetTextLineHeightWithSpacing()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.FontSize + g.Style.ItemSpacing.y;
|
|
}
|
|
|
|
float ImGui::GetFrameHeight()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.FontSize + g.Style.FramePadding.y * 2.0f;
|
|
}
|
|
|
|
float ImGui::GetFrameHeightWithSpacing()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
|
|
}
|
|
|
|
ImVec2 ImGui::GetContentRegionMax()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
|
|
if (window->DC.CurrentColumns || g.CurrentTable)
|
|
mx.x = window->WorkRect.Max.x - window->Pos.x;
|
|
return mx;
|
|
}
|
|
|
|
ImVec2 ImGui::GetContentRegionMaxAbs()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImVec2 mx = window->ContentRegionRect.Max;
|
|
if (window->DC.CurrentColumns || g.CurrentTable)
|
|
mx.x = window->WorkRect.Max.x;
|
|
return mx;
|
|
}
|
|
|
|
ImVec2 ImGui::GetContentRegionAvail()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return GetContentRegionMaxAbs() - window->DC.CursorPos;
|
|
}
|
|
|
|
ImVec2 ImGui::GetWindowContentRegionMin()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ContentRegionRect.Min - window->Pos;
|
|
}
|
|
|
|
ImVec2 ImGui::GetWindowContentRegionMax()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ContentRegionRect.Max - window->Pos;
|
|
}
|
|
|
|
float ImGui::GetWindowContentRegionWidth()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ContentRegionRect.GetWidth();
|
|
}
|
|
|
|
void ImGui::BeginGroup()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
g.GroupStack.resize(g.GroupStack.Size + 1);
|
|
ImGuiGroupData& group_data = g.GroupStack.back();
|
|
group_data.WindowID = window->ID;
|
|
group_data.BackupCursorPos = window->DC.CursorPos;
|
|
group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
|
|
group_data.BackupIndent = window->DC.Indent;
|
|
group_data.BackupGroupOffset = window->DC.GroupOffset;
|
|
group_data.BackupCurrLineSize = window->DC.CurrLineSize;
|
|
group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
|
|
group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
|
|
group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
|
|
group_data.EmitItem = true;
|
|
|
|
window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
|
|
window->DC.Indent = window->DC.GroupOffset;
|
|
window->DC.CursorMaxPos = window->DC.CursorPos;
|
|
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
|
if (g.LogEnabled)
|
|
g.LogLinePosY = -FLT_MAX;
|
|
}
|
|
|
|
void ImGui::EndGroup()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(g.GroupStack.Size > 0);
|
|
|
|
ImGuiGroupData& group_data = g.GroupStack.back();
|
|
IM_ASSERT(group_data.WindowID == window->ID);
|
|
|
|
ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
|
|
|
|
window->DC.CursorPos = group_data.BackupCursorPos;
|
|
window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
|
|
window->DC.Indent = group_data.BackupIndent;
|
|
window->DC.GroupOffset = group_data.BackupGroupOffset;
|
|
window->DC.CurrLineSize = group_data.BackupCurrLineSize;
|
|
window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
|
|
if (g.LogEnabled)
|
|
g.LogLinePosY = -FLT_MAX;
|
|
|
|
if (!group_data.EmitItem)
|
|
{
|
|
g.GroupStack.pop_back();
|
|
return;
|
|
}
|
|
|
|
window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset);
|
|
ItemSize(group_bb.GetSize());
|
|
ItemAdd(group_bb, 0);
|
|
|
|
const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
|
|
const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
|
|
if (group_contains_curr_active_id)
|
|
window->DC.LastItemId = g.ActiveId;
|
|
else if (group_contains_prev_active_id)
|
|
window->DC.LastItemId = g.ActiveIdPreviousFrame;
|
|
window->DC.LastItemRect = group_bb;
|
|
|
|
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
|
|
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
|
|
|
|
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
|
|
if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
|
|
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
|
|
|
|
g.GroupStack.pop_back();
|
|
}
|
|
|
|
|
|
static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
|
|
{
|
|
if (target <= snap_min + snap_threshold)
|
|
return ImLerp(snap_min, target, center_ratio);
|
|
if (target >= snap_max - snap_threshold)
|
|
return ImLerp(target, snap_max, center_ratio);
|
|
return target;
|
|
}
|
|
|
|
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
|
|
{
|
|
ImVec2 scroll = window->Scroll;
|
|
if (window->ScrollTarget.x < FLT_MAX)
|
|
{
|
|
float center_x_ratio = window->ScrollTargetCenterRatio.x;
|
|
float scroll_target_x = window->ScrollTarget.x;
|
|
float snap_x_min = 0.0f;
|
|
float snap_x_max = window->ScrollMax.x + window->Size.x;
|
|
if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
|
|
scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
|
|
scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x);
|
|
}
|
|
if (window->ScrollTarget.y < FLT_MAX)
|
|
{
|
|
float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
|
|
float center_y_ratio = window->ScrollTargetCenterRatio.y;
|
|
float scroll_target_y = window->ScrollTarget.y;
|
|
float snap_y_min = 0.0f;
|
|
float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height;
|
|
if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
|
|
scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
|
|
scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
|
|
}
|
|
scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
|
|
scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
|
|
if (!window->Collapsed && !window->SkipItems)
|
|
{
|
|
scroll.x = ImMin(scroll.x, window->ScrollMax.x);
|
|
scroll.y = ImMin(scroll.y, window->ScrollMax.y);
|
|
}
|
|
return scroll;
|
|
}
|
|
|
|
ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
|
|
ImVec2 delta_scroll;
|
|
if (!window_rect.Contains(item_rect))
|
|
{
|
|
if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
|
|
SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f);
|
|
else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
|
|
SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
|
|
if (item_rect.Min.y < window_rect.Min.y)
|
|
SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
|
|
else if (item_rect.Max.y >= window_rect.Max.y)
|
|
SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
|
|
|
|
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
|
|
delta_scroll = next_scroll - window->Scroll;
|
|
}
|
|
|
|
if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
|
|
|
|
return delta_scroll;
|
|
}
|
|
|
|
float ImGui::GetScrollX()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->Scroll.x;
|
|
}
|
|
|
|
float ImGui::GetScrollY()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->Scroll.y;
|
|
}
|
|
|
|
float ImGui::GetScrollMaxX()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ScrollMax.x;
|
|
}
|
|
|
|
float ImGui::GetScrollMaxY()
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
return window->ScrollMax.y;
|
|
}
|
|
|
|
void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
|
|
{
|
|
window->ScrollTarget.x = scroll_x;
|
|
window->ScrollTargetCenterRatio.x = 0.0f;
|
|
window->ScrollTargetEdgeSnapDist.x = 0.0f;
|
|
}
|
|
|
|
void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
|
|
{
|
|
window->ScrollTarget.y = scroll_y;
|
|
window->ScrollTargetCenterRatio.y = 0.0f;
|
|
window->ScrollTargetEdgeSnapDist.y = 0.0f;
|
|
}
|
|
|
|
void ImGui::SetScrollX(float scroll_x)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
SetScrollX(g.CurrentWindow, scroll_x);
|
|
}
|
|
|
|
void ImGui::SetScrollY(float scroll_y)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
SetScrollY(g.CurrentWindow, scroll_y);
|
|
}
|
|
|
|
void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
|
|
{
|
|
IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
|
|
window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x);
|
|
window->ScrollTargetCenterRatio.x = center_x_ratio;
|
|
window->ScrollTargetEdgeSnapDist.x = 0.0f;
|
|
}
|
|
|
|
void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
|
|
{
|
|
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
|
|
local_y -= window->TitleBarHeight() + window->MenuBarHeight();
|
|
window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y);
|
|
window->ScrollTargetCenterRatio.y = center_y_ratio;
|
|
window->ScrollTargetEdgeSnapDist.y = 0.0f;
|
|
}
|
|
|
|
void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
|
|
}
|
|
|
|
void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
|
|
}
|
|
|
|
void ImGui::SetScrollHereX(float center_x_ratio)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
float spacing_x = g.Style.ItemSpacing.x;
|
|
float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
|
|
SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio);
|
|
|
|
window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
|
|
}
|
|
|
|
void ImGui::SetScrollHereY(float center_y_ratio)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
float spacing_y = g.Style.ItemSpacing.y;
|
|
float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
|
|
SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio);
|
|
|
|
window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
|
|
}
|
|
|
|
void ImGui::BeginTooltip()
|
|
{
|
|
BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
|
|
}
|
|
|
|
void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (g.DragDropWithinSource || g.DragDropWithinTarget)
|
|
{
|
|
ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
|
|
SetNextWindowPos(tooltip_pos);
|
|
SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
|
|
tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip;
|
|
}
|
|
|
|
char window_name[16];
|
|
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
|
|
if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip)
|
|
if (ImGuiWindow* window = FindWindowByName(window_name))
|
|
if (window->Active)
|
|
{
|
|
window->Hidden = true;
|
|
window->HiddenFramesCanSkipItems = 1;
|
|
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
|
|
}
|
|
ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;
|
|
Begin(window_name, NULL, flags | extra_flags);
|
|
}
|
|
|
|
void ImGui::EndTooltip()
|
|
{
|
|
IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);
|
|
End();
|
|
}
|
|
|
|
void ImGui::SetTooltipV(const char* fmt, va_list args)
|
|
{
|
|
BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
|
|
TextV(fmt, args);
|
|
EndTooltip();
|
|
}
|
|
|
|
void ImGui::SetTooltip(const char* fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
SetTooltipV(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (popup_flags & ImGuiPopupFlags_AnyPopupId)
|
|
{
|
|
IM_ASSERT(id == 0);
|
|
if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
|
|
return g.OpenPopupStack.Size > 0;
|
|
else
|
|
return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
|
|
}
|
|
else
|
|
{
|
|
if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
|
|
{
|
|
for (int n = 0; n < g.OpenPopupStack.Size; n++)
|
|
if (g.OpenPopupStack[n].PopupId == id)
|
|
return true;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
|
|
if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
|
|
IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel.");
|
|
return IsPopupOpen(id, popup_flags);
|
|
}
|
|
|
|
ImGuiWindow* ImGui::GetTopMostPopupModal()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
|
|
if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
|
|
if (popup->Flags & ImGuiWindowFlags_Modal)
|
|
return popup;
|
|
return NULL;
|
|
}
|
|
|
|
void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
|
|
}
|
|
|
|
void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* parent_window = g.CurrentWindow;
|
|
const int current_stack_size = g.BeginPopupStack.Size;
|
|
|
|
if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)
|
|
if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId))
|
|
return;
|
|
|
|
ImGuiPopupData popup_ref;
|
|
popup_ref.PopupId = id;
|
|
popup_ref.Window = NULL;
|
|
popup_ref.SourceWindow = g.NavWindow;
|
|
popup_ref.OpenFrameCount = g.FrameCount;
|
|
popup_ref.OpenParentId = parent_window->IDStack.back();
|
|
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
|
|
popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
|
|
|
|
IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id);
|
|
if (g.OpenPopupStack.Size < current_stack_size + 1)
|
|
{
|
|
g.OpenPopupStack.push_back(popup_ref);
|
|
}
|
|
else
|
|
{
|
|
if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
|
|
{
|
|
g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
|
|
}
|
|
else
|
|
{
|
|
ClosePopupToLevel(current_stack_size, false);
|
|
g.OpenPopupStack.push_back(popup_ref);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.OpenPopupStack.Size == 0)
|
|
return;
|
|
|
|
int popup_count_to_keep = 0;
|
|
if (ref_window)
|
|
{
|
|
for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
|
|
{
|
|
ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
|
|
if (!popup.Window)
|
|
continue;
|
|
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
|
|
if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
continue;
|
|
|
|
bool ref_window_is_descendent_of_popup = false;
|
|
for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
|
|
if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
|
|
if (popup_window->RootWindow == ref_window->RootWindow)
|
|
{
|
|
ref_window_is_descendent_of_popup = true;
|
|
break;
|
|
}
|
|
if (!ref_window_is_descendent_of_popup)
|
|
break;
|
|
}
|
|
}
|
|
if (popup_count_to_keep < g.OpenPopupStack.Size)
|
|
{
|
|
IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
|
|
ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
|
|
}
|
|
}
|
|
|
|
void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
|
|
IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
|
|
|
|
ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
|
|
ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
|
|
g.OpenPopupStack.resize(remaining);
|
|
|
|
if (restore_focus_to_window_under_popup)
|
|
{
|
|
if (focus_window && !focus_window->WasActive && popup_window)
|
|
{
|
|
FocusTopMostWindowUnderOne(popup_window, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
|
|
focus_window = NavRestoreLastChildNavWindow(focus_window);
|
|
FocusWindow(focus_window);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImGui::CloseCurrentPopup()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
int popup_idx = g.BeginPopupStack.Size - 1;
|
|
if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
|
|
return;
|
|
|
|
while (popup_idx > 0)
|
|
{
|
|
ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
|
|
ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
|
|
bool close_parent = false;
|
|
if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
|
|
if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
|
|
close_parent = true;
|
|
if (!close_parent)
|
|
break;
|
|
popup_idx--;
|
|
}
|
|
IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
|
|
ClosePopupToLevel(popup_idx, true);
|
|
|
|
if (ImGuiWindow* window = g.NavWindow)
|
|
window->DC.NavHideHighlightOneFrame = true;
|
|
}
|
|
|
|
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
|
|
{
|
|
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
if (!IsPopupOpen(id, ImGuiPopupFlags_None))
|
|
{
|
|
g.NextWindowData.ClearFlags();
|
|
return false;
|
|
}
|
|
|
|
char name[20];
|
|
if (flags & ImGuiWindowFlags_ChildMenu)
|
|
ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size);
|
|
else
|
|
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id);
|
|
|
|
flags |= ImGuiWindowFlags_Popup;
|
|
bool is_open = Begin(name, NULL, flags);
|
|
if (!is_open)
|
|
EndPopup();
|
|
|
|
return is_open;
|
|
}
|
|
|
|
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size)
|
|
{
|
|
g.NextWindowData.ClearFlags();
|
|
return false;
|
|
}
|
|
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
|
|
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
|
|
}
|
|
|
|
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
const ImGuiID id = window->GetID(name);
|
|
if (!IsPopupOpen(id, ImGuiPopupFlags_None))
|
|
{
|
|
g.NextWindowData.ClearFlags();
|
|
return false;
|
|
}
|
|
|
|
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
|
|
SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
|
|
|
flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse;
|
|
const bool is_open = Begin(name, p_open, flags);
|
|
if (!is_open || (p_open && !*p_open))
|
|
{
|
|
EndPopup();
|
|
if (is_open)
|
|
ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
|
return false;
|
|
}
|
|
return is_open;
|
|
}
|
|
|
|
void ImGui::EndPopup()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);
|
|
IM_ASSERT(g.BeginPopupStack.Size > 0);
|
|
|
|
if (g.NavWindow == window)
|
|
NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
|
|
|
|
IM_ASSERT(g.WithinEndChild == false);
|
|
if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
|
g.WithinEndChild = true;
|
|
End();
|
|
g.WithinEndChild = false;
|
|
}
|
|
|
|
void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
|
|
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
{
|
|
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId;
|
|
IM_ASSERT(id != 0);
|
|
OpenPopupEx(id, popup_flags);
|
|
}
|
|
}
|
|
|
|
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
if (window->SkipItems)
|
|
return false;
|
|
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId;
|
|
IM_ASSERT(id != 0);
|
|
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
|
|
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
OpenPopupEx(id, popup_flags);
|
|
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
|
|
}
|
|
|
|
bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
if (!str_id)
|
|
str_id = "window_context";
|
|
ImGuiID id = window->GetID(str_id);
|
|
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
|
|
if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
|
|
if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
|
|
OpenPopupEx(id, popup_flags);
|
|
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
|
|
}
|
|
|
|
bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
{
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
if (!str_id)
|
|
str_id = "void_context";
|
|
ImGuiID id = window->GetID(str_id);
|
|
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
|
|
if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
|
|
if (GetTopMostPopupModal() == NULL)
|
|
OpenPopupEx(id, popup_flags);
|
|
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
|
|
}
|
|
|
|
ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
|
|
{
|
|
ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
|
|
if (policy == ImGuiPopupPositionPolicy_ComboBox)
|
|
{
|
|
const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
|
|
for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
|
|
{
|
|
const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
|
|
if (n != -1 && dir == *last_dir)
|
|
continue;
|
|
ImVec2 pos;
|
|
if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);
|
|
if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y);
|
|
if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y);
|
|
if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y);
|
|
if (!r_outer.Contains(ImRect(pos, pos + size)))
|
|
continue;
|
|
*last_dir = dir;
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default)
|
|
{
|
|
const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
|
|
for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
|
|
{
|
|
const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
|
|
if (n != -1 && dir == *last_dir)
|
|
continue;
|
|
|
|
const 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);
|
|
const 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);
|
|
|
|
if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
|
|
continue;
|
|
if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
|
|
continue;
|
|
|
|
ImVec2 pos;
|
|
pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
|
|
pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
|
|
|
|
pos.x = ImMax(pos.x, r_outer.Min.x);
|
|
pos.y = ImMax(pos.y, r_outer.Min.y);
|
|
|
|
*last_dir = dir;
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
*last_dir = ImGuiDir_None;
|
|
|
|
if (policy == ImGuiPopupPositionPolicy_Tooltip)
|
|
return ref_pos + ImVec2(2, 2);
|
|
|
|
ImVec2 pos = ref_pos;
|
|
pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
|
|
pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
|
|
return pos;
|
|
}
|
|
|
|
ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
|
|
{
|
|
IM_UNUSED(window);
|
|
ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
|
|
ImRect r_screen = GetViewportRect();
|
|
r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
|
|
return r_screen;
|
|
}
|
|
|
|
ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
ImRect r_outer = GetWindowAllowedExtentRect(window);
|
|
if (window->Flags & ImGuiWindowFlags_ChildMenu)
|
|
{
|
|
IM_ASSERT(g.CurrentWindow == window);
|
|
ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
|
|
float horizontal_overlap = g.Style.ItemInnerSpacing.x;
|
|
ImRect r_avoid;
|
|
if (parent_window->DC.MenuBarAppending)
|
|
r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y);
|
|
else
|
|
r_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);
|
|
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
|
|
}
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
{
|
|
ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
|
|
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
|
|
}
|
|
if (window->Flags & ImGuiWindowFlags_Tooltip)
|
|
{
|
|
float sc = g.Style.MouseCursorScale;
|
|
ImVec2 ref_pos = NavCalcPreferredRefPos();
|
|
ImRect r_avoid;
|
|
if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
|
|
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
|
|
else
|
|
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc);
|
|
return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
|
|
}
|
|
IM_ASSERT(0);
|
|
return window->Pos;
|
|
}
|
|
|
|
void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.NavWindow);
|
|
IM_ASSERT(nav_layer == 0 || nav_layer == 1);
|
|
g.NavId = id;
|
|
g.NavFocusScopeId = focus_scope_id;
|
|
g.NavWindow->NavLastIds[nav_layer] = id;
|
|
}
|
|
|
|
void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
SetNavID(id, nav_layer, focus_scope_id);
|
|
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
|
|
g.NavMousePosDirty = true;
|
|
g.NavDisableHighlight = false;
|
|
g.NavDisableMouseHover = true;
|
|
}
|
|
|
|
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(id != 0);
|
|
|
|
const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
|
|
if (g.NavWindow != window)
|
|
g.NavInitRequest = false;
|
|
g.NavWindow = window;
|
|
g.NavId = id;
|
|
g.NavLayer = nav_layer;
|
|
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
|
window->NavLastIds[nav_layer] = id;
|
|
if (window->DC.LastItemId == id)
|
|
window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
|
|
|
|
if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
|
g.NavDisableMouseHover = true;
|
|
else
|
|
g.NavDisableHighlight = true;
|
|
}
|
|
|
|
ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
|
|
{
|
|
if (ImFabs(dx) > ImFabs(dy))
|
|
return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
|
|
return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
|
|
}
|
|
|
|
static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
|
|
{
|
|
if (a1 < b0)
|
|
return a1 - b0;
|
|
if (b1 < a0)
|
|
return a0 - b1;
|
|
return 0.0f;
|
|
}
|
|
|
|
static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
|
|
{
|
|
if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
|
|
{
|
|
r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
|
|
r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
|
|
}
|
|
else
|
|
{
|
|
r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
|
|
r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
|
|
}
|
|
}
|
|
|
|
static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (g.NavLayer != window->DC.NavLayerCurrent)
|
|
return false;
|
|
|
|
const ImRect& curr = g.NavScoringRect;
|
|
g.NavScoringCount++;
|
|
|
|
if (window->ParentWindow == g.NavWindow)
|
|
{
|
|
IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
|
|
if (!window->ClipRect.Overlaps(cand))
|
|
return false;
|
|
cand.ClipWithFull(window->ClipRect);
|
|
}
|
|
|
|
NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
|
|
|
|
float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
|
|
float 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));
|
|
if (dby != 0.0f && dbx != 0.0f)
|
|
dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
|
|
float dist_box = ImFabs(dbx) + ImFabs(dby);
|
|
|
|
float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
|
|
float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
|
|
float dist_center = ImFabs(dcx) + ImFabs(dcy);
|
|
|
|
ImGuiDir quadrant;
|
|
float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
|
|
if (dbx != 0.0f || dby != 0.0f)
|
|
{
|
|
dax = dbx;
|
|
day = dby;
|
|
dist_axial = dist_box;
|
|
quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
|
|
}
|
|
else if (dcx != 0.0f || dcy != 0.0f)
|
|
{
|
|
dax = dcx;
|
|
day = dcy;
|
|
dist_axial = dist_center;
|
|
quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
|
|
}
|
|
else
|
|
{
|
|
quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
|
|
}
|
|
|
|
#if IMGUI_DEBUG_NAV_SCORING
|
|
char buf[128];
|
|
if (IsMouseHoveringRect(cand.Min, cand.Max))
|
|
{
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
|
|
ImDrawList* draw_list = GetForegroundDrawList(window);
|
|
draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
|
|
draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
|
|
draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
|
|
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
|
|
}
|
|
else if (g.IO.KeyCtrl)
|
|
{
|
|
if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
|
|
if (quadrant == g.NavMoveDir)
|
|
{
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
|
|
ImDrawList* draw_list = GetForegroundDrawList(window);
|
|
draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
|
|
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bool new_best = false;
|
|
if (quadrant == g.NavMoveDir)
|
|
{
|
|
if (dist_box < result->DistBox)
|
|
{
|
|
result->DistBox = dist_box;
|
|
result->DistCenter = dist_center;
|
|
return true;
|
|
}
|
|
if (dist_box == result->DistBox)
|
|
{
|
|
if (dist_center < result->DistCenter)
|
|
{
|
|
result->DistCenter = dist_center;
|
|
new_best = true;
|
|
}
|
|
else if (dist_center == result->DistCenter)
|
|
{
|
|
if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f)
|
|
new_best = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)
|
|
if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
|
if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f))
|
|
{
|
|
result->DistAxial = dist_axial;
|
|
new_best = true;
|
|
}
|
|
|
|
return new_best;
|
|
}
|
|
|
|
static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
|
|
{
|
|
result->Window = window;
|
|
result->ID = id;
|
|
result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
|
result->RectRel = nav_bb_rel;
|
|
}
|
|
|
|
static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
const ImGuiItemFlags item_flags = window->DC.ItemFlags;
|
|
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
|
|
|
|
if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
|
|
{
|
|
if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
|
|
{
|
|
g.NavInitResultId = id;
|
|
g.NavInitResultRectRel = nav_bb_rel;
|
|
}
|
|
if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
|
|
{
|
|
g.NavInitRequest = false;
|
|
NavUpdateAnyRequestFlag();
|
|
}
|
|
}
|
|
|
|
if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
|
{
|
|
ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
#if IMGUI_DEBUG_NAV_SCORING
|
|
if (!g.NavMoveRequest)
|
|
g.NavMoveDir = g.NavMoveDirLast;
|
|
bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
|
|
#else
|
|
bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
|
|
#endif
|
|
if (new_best)
|
|
NavApplyItemToResult(result, window, id, nav_bb_rel);
|
|
|
|
const float VISIBLE_RATIO = 0.70f;
|
|
if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
|
|
if (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)
|
|
if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
|
|
NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel);
|
|
}
|
|
|
|
if (g.NavId == id)
|
|
{
|
|
g.NavWindow = window;
|
|
g.NavLayer = window->DC.NavLayerCurrent;
|
|
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
|
g.NavIdIsAlive = true;
|
|
g.NavIdTabCounter = window->DC.FocusCounterTabStop;
|
|
window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;
|
|
}
|
|
}
|
|
|
|
bool ImGui::NavMoveRequestButNoResultYet()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
|
|
}
|
|
|
|
void ImGui::NavMoveRequestCancel()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NavMoveRequest = false;
|
|
NavUpdateAnyRequestFlag();
|
|
}
|
|
|
|
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
|
|
NavMoveRequestCancel();
|
|
g.NavMoveDir = move_dir;
|
|
g.NavMoveClipDir = clip_dir;
|
|
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
|
|
g.NavMoveRequestFlags = move_flags;
|
|
g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
|
|
}
|
|
|
|
void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
g.NavWrapRequestWindow = window;
|
|
g.NavWrapRequestFlags = move_flags;
|
|
}
|
|
|
|
static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
|
|
{
|
|
ImGuiWindow* parent = nav_window;
|
|
while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
|
|
parent = parent->ParentWindow;
|
|
if (parent && parent != nav_window)
|
|
parent->NavLastChildNavWindow = nav_window;
|
|
}
|
|
|
|
static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
|
|
{
|
|
if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive)
|
|
return window->NavLastChildNavWindow;
|
|
return window;
|
|
}
|
|
|
|
static void NavRestoreLayer(ImGuiNavLayer layer)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NavLayer = layer;
|
|
if (layer == 0)
|
|
g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow);
|
|
ImGuiWindow* window = g.NavWindow;
|
|
if (layer == 0 && window->NavLastIds[0] != 0)
|
|
ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]);
|
|
else
|
|
ImGui::NavInitWindow(window, true);
|
|
}
|
|
|
|
static inline void ImGui::NavUpdateAnyRequestFlag()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
|
|
if (g.NavAnyRequest)
|
|
IM_ASSERT(g.NavWindow != NULL);
|
|
}
|
|
|
|
void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(window == g.NavWindow);
|
|
bool init_for_nav = false;
|
|
if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
|
|
init_for_nav = true;
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
|
|
if (init_for_nav)
|
|
{
|
|
SetNavID(0, g.NavLayer, 0);
|
|
g.NavInitRequest = true;
|
|
g.NavInitRequestFromMove = false;
|
|
g.NavInitResultId = 0;
|
|
g.NavInitResultRectRel = ImRect();
|
|
NavUpdateAnyRequestFlag();
|
|
}
|
|
else
|
|
{
|
|
g.NavId = window->NavLastIds[0];
|
|
g.NavFocusScopeId = 0;
|
|
}
|
|
}
|
|
|
|
static ImVec2 ImGui::NavCalcPreferredRefPos()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
|
|
{
|
|
if (IsMousePosValid(&g.IO.MousePos))
|
|
return g.IO.MousePos;
|
|
return g.LastValidMousePos;
|
|
}
|
|
else
|
|
{
|
|
const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
|
|
ImVec2 pos = g.NavWindow->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()));
|
|
ImRect visible_rect = GetViewportRect();
|
|
return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max));
|
|
}
|
|
}
|
|
|
|
float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (mode == ImGuiInputReadMode_Down)
|
|
return g.IO.NavInputs[n];
|
|
|
|
const float t = g.IO.NavInputsDownDuration[n];
|
|
if (t < 0.0f && mode == ImGuiInputReadMode_Released)
|
|
return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
|
|
if (t < 0.0f)
|
|
return 0.0f;
|
|
if (mode == ImGuiInputReadMode_Pressed)
|
|
return (t == 0.0f) ? 1.0f : 0.0f;
|
|
if (mode == ImGuiInputReadMode_Repeat)
|
|
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
|
|
if (mode == ImGuiInputReadMode_RepeatSlow)
|
|
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
|
|
if (mode == ImGuiInputReadMode_RepeatFast)
|
|
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
|
|
return 0.0f;
|
|
}
|
|
|
|
ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
|
|
{
|
|
ImVec2 delta(0.0f, 0.0f);
|
|
if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
|
|
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode));
|
|
if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
|
|
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode));
|
|
if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
|
|
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
|
|
if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
|
|
delta *= slow_factor;
|
|
if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
|
|
delta *= fast_factor;
|
|
return delta;
|
|
}
|
|
|
|
static void ImGui::NavUpdate()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiIO& io = g.IO;
|
|
|
|
io.WantSetMousePos = false;
|
|
g.NavWrapRequestWindow = NULL;
|
|
g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
|
|
#if 0
|
|
if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
|
|
#endif
|
|
|
|
bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
|
bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
|
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad)
|
|
{
|
|
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
|
|
|| io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f)
|
|
g.NavInputSource = ImGuiInputSource_NavGamepad;
|
|
}
|
|
|
|
if (nav_keyboard_active)
|
|
{
|
|
#define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0)
|
|
NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
|
|
NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
|
|
NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
|
|
NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
|
|
NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
|
|
NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
|
|
NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
|
|
if (io.KeyCtrl)
|
|
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
|
|
if (io.KeyShift)
|
|
io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
|
|
if (io.KeyAlt && !io.KeyCtrl)
|
|
io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
|
|
#undef NAV_MAP_KEY
|
|
}
|
|
memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
|
|
for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
|
|
io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f;
|
|
|
|
if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
|
|
NavUpdateInitResult();
|
|
g.NavInitRequest = false;
|
|
g.NavInitRequestFromMove = false;
|
|
g.NavInitResultId = 0;
|
|
g.NavJustMovedToId = 0;
|
|
|
|
if (g.NavMoveRequest)
|
|
NavUpdateMoveResult();
|
|
|
|
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
|
|
{
|
|
IM_ASSERT(g.NavMoveRequest);
|
|
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
|
g.NavDisableHighlight = false;
|
|
g.NavMoveRequestForward = ImGuiNavForward_None;
|
|
}
|
|
|
|
if (g.NavMousePosDirty && g.NavIdIsAlive)
|
|
{
|
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
|
|
{
|
|
if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
|
|
{
|
|
io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
|
|
io.WantSetMousePos = true;
|
|
}
|
|
}
|
|
g.NavMousePosDirty = false;
|
|
}
|
|
g.NavIdIsAlive = false;
|
|
g.NavJustTabbedId = 0;
|
|
IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
|
|
|
|
if (g.NavWindow)
|
|
NavSaveLastChildNavWindowIntoParent(g.NavWindow);
|
|
if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
|
|
g.NavWindow->NavLastChildNavWindow = NULL;
|
|
|
|
NavUpdateWindowing();
|
|
|
|
io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
|
|
io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
|
|
|
|
if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
|
|
{
|
|
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
|
|
if (g.ActiveId != 0)
|
|
{
|
|
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
|
|
ClearActiveID();
|
|
}
|
|
else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
{
|
|
ImGuiWindow* child_window = g.NavWindow;
|
|
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
|
|
IM_ASSERT(child_window->ChildId != 0);
|
|
FocusWindow(parent_window);
|
|
SetNavID(child_window->ChildId, 0, 0);
|
|
g.NavIdIsAlive = false;
|
|
if (g.NavDisableMouseHover)
|
|
g.NavMousePosDirty = true;
|
|
}
|
|
else if (g.OpenPopupStack.Size > 0)
|
|
{
|
|
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
|
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
|
}
|
|
else if (g.NavLayer != ImGuiNavLayer_Main)
|
|
{
|
|
NavRestoreLayer(ImGuiNavLayer_Main);
|
|
}
|
|
else
|
|
{
|
|
if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
|
|
g.NavWindow->NavLastIds[0] = 0;
|
|
g.NavId = g.NavFocusScopeId = 0;
|
|
}
|
|
}
|
|
|
|
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
|
|
if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
{
|
|
bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
|
|
bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
|
|
if (g.ActiveId == 0 && activate_pressed)
|
|
g.NavActivateId = g.NavId;
|
|
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
|
|
g.NavActivateDownId = g.NavId;
|
|
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
|
|
g.NavActivatePressedId = g.NavId;
|
|
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
|
|
g.NavInputId = g.NavId;
|
|
}
|
|
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
g.NavDisableHighlight = true;
|
|
if (g.NavActivateId != 0)
|
|
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
|
|
g.NavMoveRequest = false;
|
|
|
|
if (g.NavNextActivateId != 0)
|
|
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
|
|
g.NavNextActivateId = 0;
|
|
|
|
if (g.NavMoveRequestForward == ImGuiNavForward_None)
|
|
{
|
|
g.NavMoveDir = ImGuiDir_None;
|
|
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
|
|
if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
{
|
|
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
|
|
}
|
|
g.NavMoveClipDir = g.NavMoveDir;
|
|
}
|
|
else
|
|
{
|
|
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
|
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
|
|
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
|
|
}
|
|
|
|
float nav_scoring_rect_offset_y = 0.0f;
|
|
if (nav_keyboard_active)
|
|
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
|
|
|
if (g.NavMoveDir != ImGuiDir_None)
|
|
{
|
|
g.NavMoveRequest = true;
|
|
g.NavMoveRequestKeyMods = io.KeyMods;
|
|
g.NavMoveDirLast = g.NavMoveDir;
|
|
}
|
|
if (g.NavMoveRequest && g.NavId == 0)
|
|
{
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
|
|
g.NavInitRequest = g.NavInitRequestFromMove = true;
|
|
g.NavInitResultId = 0;
|
|
g.NavDisableHighlight = false;
|
|
}
|
|
NavUpdateAnyRequestFlag();
|
|
|
|
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
|
|
{
|
|
ImGuiWindow* window = g.NavWindow;
|
|
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime);
|
|
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
|
{
|
|
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
|
|
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
|
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
|
|
SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
|
}
|
|
|
|
ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
|
|
if (scroll_dir.x != 0.0f && window->ScrollbarX)
|
|
SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
|
|
if (scroll_dir.y != 0.0f)
|
|
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
|
|
}
|
|
|
|
g.NavMoveResultLocal.Clear();
|
|
g.NavMoveResultLocalVisibleSet.Clear();
|
|
g.NavMoveResultOther.Clear();
|
|
|
|
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main)
|
|
{
|
|
ImGuiWindow* window = g.NavWindow;
|
|
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
|
|
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
|
{
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
|
|
float pad = window->CalcFontSize() * 0.5f;
|
|
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad)));
|
|
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
|
|
g.NavId = g.NavFocusScopeId = 0;
|
|
}
|
|
}
|
|
|
|
ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
|
|
g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
|
|
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
|
|
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
|
|
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
|
|
IM_ASSERT(!g.NavScoringRect.IsInverted());
|
|
g.NavScoringCount = 0;
|
|
#if IMGUI_DEBUG_NAV_RECTS
|
|
if (g.NavWindow)
|
|
{
|
|
ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
|
|
if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); }
|
|
if (1) { ImU32 col = (!g.NavWindow->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); }
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void ImGui::NavUpdateInitResult()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.NavWindow)
|
|
return;
|
|
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
|
|
if (g.NavInitRequestFromMove)
|
|
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
|
|
else
|
|
SetNavID(g.NavInitResultId, g.NavLayer, 0);
|
|
g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
|
|
}
|
|
|
|
static void ImGui::NavUpdateMoveResult()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
|
{
|
|
if (g.NavId != 0)
|
|
{
|
|
g.NavDisableHighlight = false;
|
|
g.NavDisableMouseHover = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
|
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
|
|
if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
|
|
result = &g.NavMoveResultLocalVisibleSet;
|
|
|
|
if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
|
|
if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
|
|
result = &g.NavMoveResultOther;
|
|
IM_ASSERT(g.NavWindow && result->Window);
|
|
|
|
if (g.NavLayer == ImGuiNavLayer_Main)
|
|
{
|
|
ImVec2 delta_scroll;
|
|
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
|
|
{
|
|
float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
|
|
delta_scroll.y = result->Window->Scroll.y - scroll_target;
|
|
SetScrollY(result->Window, scroll_target);
|
|
}
|
|
else
|
|
{
|
|
ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
|
|
delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
|
|
}
|
|
|
|
result->RectRel.TranslateX(-delta_scroll.x);
|
|
result->RectRel.TranslateY(-delta_scroll.y);
|
|
}
|
|
|
|
ClearActiveID();
|
|
g.NavWindow = result->Window;
|
|
if (g.NavId != result->ID)
|
|
{
|
|
g.NavJustMovedToId = result->ID;
|
|
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
|
|
g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
|
|
}
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
|
|
SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
|
|
}
|
|
|
|
static float ImGui::NavUpdatePageUpPageDown()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiIO& io = g.IO;
|
|
|
|
if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
|
|
return 0.0f;
|
|
if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
|
|
return 0.0f;
|
|
|
|
ImGuiWindow* window = g.NavWindow;
|
|
const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
|
|
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
|
|
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
|
|
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
|
|
if (page_up_held != page_down_held || home_pressed != end_pressed)
|
|
{
|
|
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
|
|
{
|
|
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
|
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
|
|
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
|
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
|
|
else if (home_pressed)
|
|
SetScrollY(window, 0.0f);
|
|
else if (end_pressed)
|
|
SetScrollY(window, window->ScrollMax.y);
|
|
}
|
|
else
|
|
{
|
|
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
|
|
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
|
|
float nav_scoring_rect_offset_y = 0.0f;
|
|
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
|
{
|
|
nav_scoring_rect_offset_y = -page_offset_y;
|
|
g.NavMoveDir = ImGuiDir_Down;
|
|
g.NavMoveClipDir = ImGuiDir_Up;
|
|
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
|
}
|
|
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
|
{
|
|
nav_scoring_rect_offset_y = +page_offset_y;
|
|
g.NavMoveDir = ImGuiDir_Up;
|
|
g.NavMoveClipDir = ImGuiDir_Down;
|
|
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
|
}
|
|
else if (home_pressed)
|
|
{
|
|
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
|
|
if (nav_rect_rel.IsInverted())
|
|
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
|
g.NavMoveDir = ImGuiDir_Down;
|
|
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
|
}
|
|
else if (end_pressed)
|
|
{
|
|
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
|
|
if (nav_rect_rel.IsInverted())
|
|
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
|
g.NavMoveDir = ImGuiDir_Up;
|
|
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
|
}
|
|
return nav_scoring_rect_offset_y;
|
|
}
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
static void ImGui::NavEndFrame()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
if (g.NavWindowingTarget != NULL)
|
|
NavUpdateWindowingOverlay();
|
|
|
|
ImGuiWindow* window = g.NavWrapRequestWindow;
|
|
ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags;
|
|
if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main)
|
|
{
|
|
IM_ASSERT(move_flags != 0);
|
|
ImRect bb_rel = window->NavRectRel[0];
|
|
|
|
ImGuiDir clip_dir = g.NavMoveDir;
|
|
if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
|
|
{
|
|
bb_rel.Min.x = bb_rel.Max.x =
|
|
ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
|
|
if (move_flags & ImGuiNavMoveFlags_WrapX)
|
|
{
|
|
bb_rel.TranslateY(-bb_rel.GetHeight());
|
|
clip_dir = ImGuiDir_Up;
|
|
}
|
|
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
|
}
|
|
if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
|
|
{
|
|
bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
|
|
if (move_flags & ImGuiNavMoveFlags_WrapX)
|
|
{
|
|
bb_rel.TranslateY(+bb_rel.GetHeight());
|
|
clip_dir = ImGuiDir_Down;
|
|
}
|
|
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
|
}
|
|
if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
|
|
{
|
|
bb_rel.Min.y = bb_rel.Max.y =
|
|
ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
|
|
if (move_flags & ImGuiNavMoveFlags_WrapY)
|
|
{
|
|
bb_rel.TranslateX(-bb_rel.GetWidth());
|
|
clip_dir = ImGuiDir_Left;
|
|
}
|
|
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
|
}
|
|
if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
|
|
{
|
|
bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
|
|
if (move_flags & ImGuiNavMoveFlags_WrapY)
|
|
{
|
|
bb_rel.TranslateX(+bb_rel.GetWidth());
|
|
clip_dir = ImGuiDir_Right;
|
|
}
|
|
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
|
|
if (g.WindowsFocusOrder[i] == window)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
|
|
if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
|
|
return g.WindowsFocusOrder[i];
|
|
return NULL;
|
|
}
|
|
|
|
static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.NavWindowingTarget);
|
|
if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
|
|
return;
|
|
|
|
const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
|
|
ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
|
|
if (!window_target)
|
|
window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
|
|
if (window_target)
|
|
g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
|
|
g.NavWindowingToggleLayer = false;
|
|
}
|
|
|
|
static void ImGui::NavUpdateWindowing()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* apply_focus_window = NULL;
|
|
bool apply_toggle_layer = false;
|
|
|
|
ImGuiWindow* modal_window = GetTopMostPopupModal();
|
|
bool allow_windowing = (modal_window == NULL);
|
|
if (!allow_windowing)
|
|
g.NavWindowingTarget = NULL;
|
|
|
|
if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
|
|
{
|
|
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
|
|
if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
|
|
g.NavWindowingTargetAnim = NULL;
|
|
}
|
|
|
|
bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
|
|
bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
|
|
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
|
|
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
|
|
{
|
|
g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow;
|
|
g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
|
|
g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
|
|
g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
|
|
}
|
|
|
|
g.NavWindowingTimer += g.IO.DeltaTime;
|
|
if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
|
|
{
|
|
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
|
|
|
|
const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
|
|
if (focus_change_dir != 0)
|
|
{
|
|
NavUpdateWindowingHighlightWindow(focus_change_dir);
|
|
g.NavWindowingHighlightAlpha = 1.0f;
|
|
}
|
|
|
|
if (!IsNavInputDown(ImGuiNavInput_Menu))
|
|
{
|
|
g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f);
|
|
if (g.NavWindowingToggleLayer && g.NavWindow)
|
|
apply_toggle_layer = true;
|
|
else if (!g.NavWindowingToggleLayer)
|
|
apply_focus_window = g.NavWindowingTarget;
|
|
g.NavWindowingTarget = NULL;
|
|
}
|
|
}
|
|
|
|
if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
|
|
{
|
|
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
|
|
if (IsKeyPressedMap(ImGuiKey_Tab, true))
|
|
NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
|
|
if (!g.IO.KeyCtrl)
|
|
apply_focus_window = g.NavWindowingTarget;
|
|
}
|
|
|
|
if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
|
|
g.NavWindowingToggleLayer = true;
|
|
if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
|
|
if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
|
|
apply_toggle_layer = true;
|
|
|
|
if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
|
|
{
|
|
ImVec2 move_delta;
|
|
if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
|
|
move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
|
|
if (g.NavInputSource == ImGuiInputSource_NavGamepad)
|
|
move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
|
|
if (move_delta.x != 0.0f || move_delta.y != 0.0f)
|
|
{
|
|
const float NAV_MOVE_SPEED = 800.0f;
|
|
const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
|
|
ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;
|
|
SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
|
|
MarkIniSettingsDirty(moving_window);
|
|
g.NavDisableMouseHover = true;
|
|
}
|
|
}
|
|
|
|
if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
|
|
{
|
|
ClearActiveID();
|
|
g.NavDisableHighlight = false;
|
|
g.NavDisableMouseHover = true;
|
|
apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
|
|
ClosePopupsOverWindow(apply_focus_window, false);
|
|
FocusWindow(apply_focus_window);
|
|
if (apply_focus_window->NavLastIds[0] == 0)
|
|
NavInitWindow(apply_focus_window, false);
|
|
|
|
if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
|
|
g.NavLayer = ImGuiNavLayer_Menu;
|
|
}
|
|
if (apply_focus_window)
|
|
g.NavWindowingTarget = NULL;
|
|
|
|
if (apply_toggle_layer && g.NavWindow)
|
|
{
|
|
ImGuiWindow* new_nav_window = g.NavWindow;
|
|
while (new_nav_window->ParentWindow
|
|
&& (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
|
|
&& (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
|
|
&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
|
|
new_nav_window = new_nav_window->ParentWindow;
|
|
if (new_nav_window != g.NavWindow)
|
|
{
|
|
ImGuiWindow* old_nav_window = g.NavWindow;
|
|
FocusWindow(new_nav_window);
|
|
new_nav_window->NavLastChildNavWindow = old_nav_window;
|
|
}
|
|
g.NavDisableHighlight = false;
|
|
g.NavDisableMouseHover = true;
|
|
|
|
const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
|
|
NavRestoreLayer(new_nav_layer);
|
|
}
|
|
}
|
|
|
|
static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
|
|
{
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
return "(Popup)";
|
|
if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
|
|
return "(Main menu bar)";
|
|
return "(Untitled)";
|
|
}
|
|
|
|
void ImGui::NavUpdateWindowingOverlay()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.NavWindowingTarget != NULL);
|
|
|
|
if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
|
|
return;
|
|
|
|
if (g.NavWindowingListWindow == NULL)
|
|
g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
|
|
SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
|
|
SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
|
PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
|
|
Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
|
|
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
|
|
{
|
|
ImGuiWindow* window = g.WindowsFocusOrder[n];
|
|
if (!IsWindowNavFocusable(window))
|
|
continue;
|
|
const char* label = window->Name;
|
|
if (label == FindRenderedTextEnd(label))
|
|
label = GetFallbackWindowNameForWindowingList(window);
|
|
Selectable(label, g.NavWindowingTarget == window);
|
|
}
|
|
End();
|
|
PopStyleVar();
|
|
}
|
|
|
|
|
|
void ImGui::ClearDragDrop()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.DragDropActive = false;
|
|
g.DragDropPayload.Clear();
|
|
g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
|
|
g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
|
|
g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
|
|
g.DragDropAcceptFrameCount = -1;
|
|
|
|
g.DragDropPayloadBufHeap.clear();
|
|
memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
|
|
}
|
|
|
|
bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
bool source_drag_active = false;
|
|
ImGuiID source_id = 0;
|
|
ImGuiID source_parent_id = 0;
|
|
ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
|
|
if (!(flags & ImGuiDragDropFlags_SourceExtern))
|
|
{
|
|
source_id = window->DC.LastItemId;
|
|
if (source_id != 0 && g.ActiveId != source_id)
|
|
return false;
|
|
if (g.IO.MouseDown[mouse_button] == false)
|
|
return false;
|
|
|
|
if (source_id == 0)
|
|
{
|
|
if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
|
|
{
|
|
IM_ASSERT(0);
|
|
return false;
|
|
}
|
|
|
|
if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
|
|
return false;
|
|
|
|
source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
|
|
bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
|
|
if (is_hovered && g.IO.MouseClicked[mouse_button])
|
|
{
|
|
SetActiveID(source_id, window);
|
|
FocusWindow(window);
|
|
}
|
|
if (g.ActiveId == source_id)
|
|
g.ActiveIdAllowOverlap = is_hovered;
|
|
}
|
|
else
|
|
{
|
|
g.ActiveIdAllowOverlap = false;
|
|
}
|
|
if (g.ActiveId != source_id)
|
|
return false;
|
|
source_parent_id = window->IDStack.back();
|
|
source_drag_active = IsMouseDragging(mouse_button);
|
|
|
|
g.ActiveIdUsingNavDirMask = ~(ImU32)0;
|
|
g.ActiveIdUsingNavInputMask = ~(ImU32)0;
|
|
g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
|
|
}
|
|
else
|
|
{
|
|
window = NULL;
|
|
source_id = ImHashStr("#SourceExtern");
|
|
source_drag_active = true;
|
|
}
|
|
|
|
if (source_drag_active)
|
|
{
|
|
if (!g.DragDropActive)
|
|
{
|
|
IM_ASSERT(source_id != 0);
|
|
ClearDragDrop();
|
|
ImGuiPayload& payload = g.DragDropPayload;
|
|
payload.SourceId = source_id;
|
|
payload.SourceParentId = source_parent_id;
|
|
g.DragDropActive = true;
|
|
g.DragDropSourceFlags = flags;
|
|
g.DragDropMouseButton = mouse_button;
|
|
if (payload.SourceId == g.ActiveId)
|
|
g.ActiveIdNoClearOnFocusLoss = true;
|
|
}
|
|
g.DragDropSourceFrameCount = g.FrameCount;
|
|
g.DragDropWithinSource = true;
|
|
|
|
if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
|
|
{
|
|
BeginTooltip();
|
|
if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
|
|
{
|
|
ImGuiWindow* tooltip_window = g.CurrentWindow;
|
|
tooltip_window->SkipItems = true;
|
|
tooltip_window->HiddenFramesCanSkipItems = 1;
|
|
}
|
|
}
|
|
|
|
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
|
|
window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ImGui::EndDragDropSource()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.DragDropActive);
|
|
IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
|
|
|
|
if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
|
|
EndTooltip();
|
|
|
|
if (g.DragDropPayload.DataFrameCount == -1)
|
|
ClearDragDrop();
|
|
g.DragDropWithinSource = false;
|
|
}
|
|
|
|
bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiPayload& payload = g.DragDropPayload;
|
|
if (cond == 0)
|
|
cond = ImGuiCond_Always;
|
|
|
|
IM_ASSERT(type != NULL);
|
|
IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
|
|
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
|
|
IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
|
|
IM_ASSERT(payload.SourceId != 0);
|
|
|
|
if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
|
|
{
|
|
ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
|
|
g.DragDropPayloadBufHeap.resize(0);
|
|
if (data_size > sizeof(g.DragDropPayloadBufLocal))
|
|
{
|
|
g.DragDropPayloadBufHeap.resize((int)data_size);
|
|
payload.Data = g.DragDropPayloadBufHeap.Data;
|
|
memcpy(payload.Data, data, data_size);
|
|
}
|
|
else if (data_size > 0)
|
|
{
|
|
memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
|
|
payload.Data = g.DragDropPayloadBufLocal;
|
|
memcpy(payload.Data, data, data_size);
|
|
}
|
|
else
|
|
{
|
|
payload.Data = NULL;
|
|
}
|
|
payload.DataSize = (int)data_size;
|
|
}
|
|
payload.DataFrameCount = g.FrameCount;
|
|
|
|
return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
|
|
}
|
|
|
|
bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.DragDropActive)
|
|
return false;
|
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
|
|
if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
|
|
return false;
|
|
IM_ASSERT(id != 0);
|
|
if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
|
|
return false;
|
|
if (window->SkipItems)
|
|
return false;
|
|
|
|
IM_ASSERT(g.DragDropWithinTarget == false);
|
|
g.DragDropTargetRect = bb;
|
|
g.DragDropTargetId = id;
|
|
g.DragDropWithinTarget = true;
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::BeginDragDropTarget()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.DragDropActive)
|
|
return false;
|
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
|
|
return false;
|
|
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
|
|
if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
|
|
return false;
|
|
|
|
const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
|
|
ImGuiID id = window->DC.LastItemId;
|
|
if (id == 0)
|
|
id = window->GetIDFromRectangle(display_rect);
|
|
if (g.DragDropPayload.SourceId == id)
|
|
return false;
|
|
|
|
IM_ASSERT(g.DragDropWithinTarget == false);
|
|
g.DragDropTargetRect = display_rect;
|
|
g.DragDropTargetId = id;
|
|
g.DragDropWithinTarget = true;
|
|
return true;
|
|
}
|
|
|
|
bool ImGui::IsDragDropPayloadBeingAccepted()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
|
|
}
|
|
|
|
const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiPayload& payload = g.DragDropPayload;
|
|
IM_ASSERT(g.DragDropActive);
|
|
IM_ASSERT(payload.DataFrameCount != -1);
|
|
if (type != NULL && !payload.IsDataType(type))
|
|
return NULL;
|
|
|
|
const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
|
|
ImRect r = g.DragDropTargetRect;
|
|
float r_surface = r.GetWidth() * r.GetHeight();
|
|
if (r_surface <= g.DragDropAcceptIdCurrRectSurface)
|
|
{
|
|
g.DragDropAcceptFlags = flags;
|
|
g.DragDropAcceptIdCurr = g.DragDropTargetId;
|
|
g.DragDropAcceptIdCurrRectSurface = r_surface;
|
|
}
|
|
|
|
payload.Preview = was_accepted_previously;
|
|
flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect);
|
|
if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
|
|
{
|
|
r.Expand(3.5f);
|
|
bool push_clip_rect = !window->ClipRect.Contains(r);
|
|
if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1));
|
|
window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
|
|
if (push_clip_rect) window->DrawList->PopClipRect();
|
|
}
|
|
|
|
g.DragDropAcceptFrameCount = g.FrameCount;
|
|
payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton);
|
|
if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
|
|
return NULL;
|
|
|
|
return &payload;
|
|
}
|
|
|
|
const ImGuiPayload* ImGui::GetDragDropPayload()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.DragDropActive ? &g.DragDropPayload : NULL;
|
|
}
|
|
|
|
void ImGui::EndDragDropTarget()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.DragDropActive);
|
|
IM_ASSERT(g.DragDropWithinTarget);
|
|
g.DragDropWithinTarget = false;
|
|
}
|
|
|
|
void ImGui::LogText(const char* fmt, ...)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.LogEnabled)
|
|
return;
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
if (g.LogFile)
|
|
{
|
|
g.LogBuffer.Buf.resize(0);
|
|
g.LogBuffer.appendfv(fmt, args);
|
|
ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
|
|
}
|
|
else
|
|
{
|
|
g.LogBuffer.appendfv(fmt, args);
|
|
}
|
|
va_end(args);
|
|
}
|
|
|
|
void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
const char* prefix = g.LogNextPrefix;
|
|
const char* suffix = g.LogNextSuffix;
|
|
g.LogNextPrefix = g.LogNextSuffix = NULL;
|
|
|
|
if (!text_end)
|
|
text_end = FindRenderedTextEnd(text, text_end);
|
|
|
|
const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);
|
|
if (ref_pos)
|
|
g.LogLinePosY = ref_pos->y;
|
|
if (log_new_line)
|
|
{
|
|
LogText(IM_NEWLINE);
|
|
g.LogLineFirstItem = true;
|
|
}
|
|
|
|
if (prefix)
|
|
LogRenderedText(ref_pos, prefix, prefix + strlen(prefix));
|
|
|
|
if (g.LogDepthRef > window->DC.TreeDepth)
|
|
g.LogDepthRef = window->DC.TreeDepth;
|
|
const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
|
|
|
|
const char* text_remaining = text;
|
|
for (;;)
|
|
{
|
|
const char* line_start = text_remaining;
|
|
const char* line_end = ImStreolRange(line_start, text_end);
|
|
const bool is_last_line = (line_end == text_end);
|
|
if (line_start != line_end || !is_last_line)
|
|
{
|
|
const int line_length = (int)(line_end - line_start);
|
|
const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1;
|
|
LogText("%*s%.*s", indentation, "", line_length, line_start);
|
|
g.LogLineFirstItem = false;
|
|
if (*line_end == '\n')
|
|
{
|
|
LogText(IM_NEWLINE);
|
|
g.LogLineFirstItem = true;
|
|
}
|
|
}
|
|
if (is_last_line)
|
|
break;
|
|
text_remaining = line_end + 1;
|
|
}
|
|
|
|
if (suffix)
|
|
LogRenderedText(ref_pos, suffix, suffix + strlen(suffix));
|
|
}
|
|
|
|
void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
IM_ASSERT(g.LogEnabled == false);
|
|
IM_ASSERT(g.LogFile == NULL);
|
|
IM_ASSERT(g.LogBuffer.empty());
|
|
g.LogEnabled = true;
|
|
g.LogType = type;
|
|
g.LogNextPrefix = g.LogNextSuffix = NULL;
|
|
g.LogDepthRef = window->DC.TreeDepth;
|
|
g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
|
|
g.LogLinePosY = FLT_MAX;
|
|
g.LogLineFirstItem = true;
|
|
}
|
|
|
|
void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.LogNextPrefix = prefix;
|
|
g.LogNextSuffix = suffix;
|
|
}
|
|
|
|
void ImGui::LogToTTY(int auto_open_depth)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.LogEnabled)
|
|
return;
|
|
IM_UNUSED(auto_open_depth);
|
|
#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
|
|
LogBegin(ImGuiLogType_TTY, auto_open_depth);
|
|
g.LogFile = stdout;
|
|
#endif
|
|
}
|
|
|
|
void ImGui::LogToFile(int auto_open_depth, const char* filename)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.LogEnabled)
|
|
return;
|
|
|
|
if (!filename)
|
|
filename = g.IO.LogFilename;
|
|
if (!filename || !filename[0])
|
|
return;
|
|
ImFileHandle f = ImFileOpen(filename, "ab");
|
|
if (!f)
|
|
{
|
|
IM_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
LogBegin(ImGuiLogType_File, auto_open_depth);
|
|
g.LogFile = f;
|
|
}
|
|
|
|
void ImGui::LogToClipboard(int auto_open_depth)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.LogEnabled)
|
|
return;
|
|
LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
|
|
}
|
|
|
|
void ImGui::LogToBuffer(int auto_open_depth)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.LogEnabled)
|
|
return;
|
|
LogBegin(ImGuiLogType_Buffer, auto_open_depth);
|
|
}
|
|
|
|
void ImGui::LogFinish()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.LogEnabled)
|
|
return;
|
|
|
|
LogText(IM_NEWLINE);
|
|
switch (g.LogType)
|
|
{
|
|
case ImGuiLogType_TTY:
|
|
#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
|
|
fflush(g.LogFile);
|
|
#endif
|
|
break;
|
|
case ImGuiLogType_File:
|
|
ImFileClose(g.LogFile);
|
|
break;
|
|
case ImGuiLogType_Buffer:
|
|
break;
|
|
case ImGuiLogType_Clipboard:
|
|
if (!g.LogBuffer.empty())
|
|
SetClipboardText(g.LogBuffer.begin());
|
|
break;
|
|
case ImGuiLogType_None:
|
|
IM_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
g.LogEnabled = false;
|
|
g.LogType = ImGuiLogType_None;
|
|
g.LogFile = NULL;
|
|
g.LogBuffer.clear();
|
|
}
|
|
|
|
void ImGui::LogButtons()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
PushID("LogButtons");
|
|
#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
|
|
const bool log_to_tty = Button("Log To TTY"); SameLine();
|
|
#else
|
|
const bool log_to_tty = false;
|
|
#endif
|
|
const bool log_to_file = Button("Log To File"); SameLine();
|
|
const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
|
|
PushAllowKeyboardFocus(false);
|
|
SetNextItemWidth(80.0f);
|
|
SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
|
|
PopAllowKeyboardFocus();
|
|
PopID();
|
|
|
|
if (log_to_tty)
|
|
LogToTTY();
|
|
if (log_to_file)
|
|
LogToFile();
|
|
if (log_to_clipboard)
|
|
LogToClipboard();
|
|
}
|
|
|
|
|
|
void ImGui::UpdateSettings()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!g.SettingsLoaded)
|
|
{
|
|
IM_ASSERT(g.SettingsWindows.empty());
|
|
if (g.IO.IniFilename)
|
|
LoadIniSettingsFromDisk(g.IO.IniFilename);
|
|
g.SettingsLoaded = true;
|
|
}
|
|
|
|
if (g.SettingsDirtyTimer > 0.0f)
|
|
{
|
|
g.SettingsDirtyTimer -= g.IO.DeltaTime;
|
|
if (g.SettingsDirtyTimer <= 0.0f)
|
|
{
|
|
if (g.IO.IniFilename != NULL)
|
|
SaveIniSettingsToDisk(g.IO.IniFilename);
|
|
else
|
|
g.IO.WantSaveIniSettings = true;
|
|
g.SettingsDirtyTimer = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImGui::MarkIniSettingsDirty()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (g.SettingsDirtyTimer <= 0.0f)
|
|
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
|
}
|
|
|
|
void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
|
|
if (g.SettingsDirtyTimer <= 0.0f)
|
|
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
|
}
|
|
|
|
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
#if !IMGUI_DEBUG_INI_SETTINGS
|
|
if (const char* p = strstr(name, "###"))
|
|
name = p;
|
|
#endif
|
|
const size_t name_len = strlen(name);
|
|
|
|
const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
|
|
ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
|
|
IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
|
|
settings->ID = ImHashStr(name, name_len);
|
|
memcpy(settings->GetName(), name, name_len + 1);
|
|
|
|
return settings;
|
|
}
|
|
|
|
ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
|
|
if (settings->ID == id)
|
|
return settings;
|
|
return NULL;
|
|
}
|
|
|
|
ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
|
|
{
|
|
if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
|
|
return settings;
|
|
return CreateNewWindowSettings(name);
|
|
}
|
|
|
|
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
const ImGuiID type_hash = ImHashStr(type_name);
|
|
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
|
if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
|
|
return &g.SettingsHandlers[handler_n];
|
|
return NULL;
|
|
}
|
|
|
|
void ImGui::ClearIniSettings()
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.SettingsIniData.clear();
|
|
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
|
if (g.SettingsHandlers[handler_n].ClearAllFn)
|
|
g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
|
|
}
|
|
|
|
void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
|
|
{
|
|
size_t file_data_size = 0;
|
|
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
|
|
if (!file_data)
|
|
return;
|
|
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
|
|
IM_FREE(file_data);
|
|
}
|
|
|
|
void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
IM_ASSERT(g.Initialized);
|
|
if (ini_size == 0)
|
|
ini_size = strlen(ini_data);
|
|
g.SettingsIniData.Buf.resize((int)ini_size + 1);
|
|
char* const buf = g.SettingsIniData.Buf.Data;
|
|
char* const buf_end = buf + ini_size;
|
|
memcpy(buf, ini_data, ini_size);
|
|
buf_end[0] = 0;
|
|
|
|
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
|
if (g.SettingsHandlers[handler_n].ReadInitFn)
|
|
g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
|
|
|
|
void* entry_data = NULL;
|
|
ImGuiSettingsHandler* entry_handler = NULL;
|
|
|
|
char* line_end = NULL;
|
|
for (char* line = buf; line < buf_end; line = line_end + 1)
|
|
{
|
|
while (*line == '\n' || *line == '\r')
|
|
line++;
|
|
line_end = line;
|
|
while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
|
|
line_end++;
|
|
line_end[0] = 0;
|
|
if (line[0] == ';')
|
|
continue;
|
|
if (line[0] == '[' && line_end > line && line_end[-1] == ']')
|
|
{
|
|
line_end[-1] = 0;
|
|
const char* name_end = line_end - 1;
|
|
const char* type_start = line + 1;
|
|
char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
|
|
const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
|
|
if (!type_end || !name_start)
|
|
continue;
|
|
*type_end = 0;
|
|
name_start++;
|
|
entry_handler = FindSettingsHandler(type_start);
|
|
entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
|
|
}
|
|
else if (entry_handler != NULL && entry_data != NULL)
|
|
{
|
|
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
|
|
}
|
|
}
|
|
g.SettingsLoaded = true;
|
|
|
|
memcpy(buf, ini_data, ini_size);
|
|
|
|
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
|
if (g.SettingsHandlers[handler_n].ApplyAllFn)
|
|
g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
|
|
}
|
|
|
|
void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.SettingsDirtyTimer = 0.0f;
|
|
if (!ini_filename)
|
|
return;
|
|
|
|
size_t ini_data_size = 0;
|
|
const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
|
|
ImFileHandle f = ImFileOpen(ini_filename, "wt");
|
|
if (!f)
|
|
return;
|
|
ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
|
|
ImFileClose(f);
|
|
}
|
|
|
|
const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.SettingsDirtyTimer = 0.0f;
|
|
g.SettingsIniData.Buf.resize(0);
|
|
g.SettingsIniData.Buf.push_back(0);
|
|
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
|
{
|
|
ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
|
|
handler->WriteAllFn(&g, handler, &g.SettingsIniData);
|
|
}
|
|
if (out_size)
|
|
*out_size = (size_t)g.SettingsIniData.size();
|
|
return g.SettingsIniData.c_str();
|
|
}
|
|
|
|
static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
g.Windows[i]->SettingsOffset = -1;
|
|
g.SettingsWindows.clear();
|
|
}
|
|
|
|
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
|
|
{
|
|
ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name);
|
|
ImGuiID id = settings->ID;
|
|
*settings = ImGuiWindowSettings();
|
|
settings->ID = id;
|
|
settings->WantApply = true;
|
|
return (void*)settings;
|
|
}
|
|
|
|
static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
|
|
{
|
|
ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
|
|
int x, y;
|
|
int i;
|
|
if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); }
|
|
else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }
|
|
else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
|
|
}
|
|
|
|
static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
|
|
if (settings->WantApply)
|
|
{
|
|
if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
|
|
ApplyWindowSettings(window, settings);
|
|
settings->WantApply = false;
|
|
}
|
|
}
|
|
|
|
static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
|
|
{
|
|
ImGuiContext& g = *ctx;
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
{
|
|
ImGuiWindow* window = g.Windows[i];
|
|
if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
|
|
continue;
|
|
|
|
ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
|
|
if (!settings)
|
|
{
|
|
settings = ImGui::CreateNewWindowSettings(window->Name);
|
|
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
|
|
}
|
|
IM_ASSERT(settings->ID == window->ID);
|
|
settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
|
|
settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
|
|
settings->Collapsed = window->Collapsed;
|
|
}
|
|
|
|
buf->reserve(buf->size() + g.SettingsWindows.size() * 6);
|
|
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
|
|
{
|
|
const char* settings_name = settings->GetName();
|
|
buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
|
|
buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
|
|
buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
|
|
buf->appendf("Collapsed=%d\n", settings->Collapsed);
|
|
buf->append("\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma comment(lib, "user32")
|
|
#pragma comment(lib, "kernel32")
|
|
#endif
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl(void*)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.ClipboardHandlerData.clear();
|
|
if (!::OpenClipboard(NULL))
|
|
return NULL;
|
|
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
|
|
if (wbuf_handle == NULL)
|
|
{
|
|
::CloseClipboard();
|
|
return NULL;
|
|
}
|
|
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
|
|
{
|
|
int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
|
|
g.ClipboardHandlerData.resize(buf_len);
|
|
::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
|
|
}
|
|
::GlobalUnlock(wbuf_handle);
|
|
::CloseClipboard();
|
|
return g.ClipboardHandlerData.Data;
|
|
}
|
|
|
|
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
|
|
{
|
|
if (!::OpenClipboard(NULL))
|
|
return;
|
|
const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
|
|
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
|
|
if (wbuf_handle == NULL)
|
|
{
|
|
::CloseClipboard();
|
|
return;
|
|
}
|
|
WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
|
|
::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
|
|
::GlobalUnlock(wbuf_handle);
|
|
::EmptyClipboard();
|
|
if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
|
|
::GlobalFree(wbuf_handle);
|
|
::CloseClipboard();
|
|
}
|
|
|
|
#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
|
|
|
|
#include <Carbon/Carbon.h>
|
|
static PasteboardRef main_clipboard = 0;
|
|
|
|
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
|
|
{
|
|
if (!main_clipboard)
|
|
PasteboardCreate(kPasteboardClipboard, &main_clipboard);
|
|
PasteboardClear(main_clipboard);
|
|
CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
|
|
if (cf_data)
|
|
{
|
|
PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
|
|
CFRelease(cf_data);
|
|
}
|
|
}
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl(void*)
|
|
{
|
|
if (!main_clipboard)
|
|
PasteboardCreate(kPasteboardClipboard, &main_clipboard);
|
|
PasteboardSynchronize(main_clipboard);
|
|
|
|
ItemCount item_count = 0;
|
|
PasteboardGetItemCount(main_clipboard, &item_count);
|
|
for (ItemCount i = 0; i < item_count; i++)
|
|
{
|
|
PasteboardItemID item_id = 0;
|
|
PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
|
|
CFArrayRef flavor_type_array = 0;
|
|
PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
|
|
for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
|
|
{
|
|
CFDataRef cf_data;
|
|
if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.ClipboardHandlerData.clear();
|
|
int length = (int)CFDataGetLength(cf_data);
|
|
g.ClipboardHandlerData.resize(length + 1);
|
|
CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
|
|
g.ClipboardHandlerData[length] = 0;
|
|
CFRelease(cf_data);
|
|
return g.ClipboardHandlerData.Data;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl(void*)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
|
|
}
|
|
|
|
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
g.ClipboardHandlerData.clear();
|
|
const char* text_end = text + strlen(text);
|
|
g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
|
|
memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
|
|
g.ClipboardHandlerData[(int)(text_end - text)] = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
|
|
|
|
#include <imm.h>
|
|
#ifdef _MSC_VER
|
|
#pragma comment(lib, "imm32")
|
|
#endif
|
|
|
|
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
if (HWND hwnd = (HWND)io.ImeWindowHandle)
|
|
if (HIMC himc = ::ImmGetContext(hwnd))
|
|
{
|
|
COMPOSITIONFORM cf;
|
|
cf.ptCurrentPos.x = x;
|
|
cf.ptCurrentPos.y = y;
|
|
cf.dwStyle = CFS_FORCE_POSITION;
|
|
::ImmSetCompositionWindow(himc, &cf);
|
|
::ImmReleaseContext(hwnd, himc);
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
|
|
|
|
#endif
|
|
|
|
#ifndef IMGUI_DISABLE_METRICS_WINDOW
|
|
|
|
static void MetricsHelpMarker(const char* desc)
|
|
{
|
|
ImGui::TextDisabled("(?)");
|
|
if (ImGui::IsItemHovered())
|
|
{
|
|
ImGui::BeginTooltip();
|
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
|
ImGui::TextUnformatted(desc);
|
|
ImGui::PopTextWrapPos();
|
|
ImGui::EndTooltip();
|
|
}
|
|
}
|
|
|
|
void ImGui::ShowMetricsWindow(bool* p_open)
|
|
{
|
|
if (!Begin("Dear ImGui Metrics/Debugger", p_open))
|
|
{
|
|
End();
|
|
return;
|
|
}
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiIO& io = g.IO;
|
|
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
|
|
|
|
Text("Dear ImGui %s", ImGui::GetVersion());
|
|
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
|
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
|
|
Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
|
|
Text("%d active allocations", io.MetricsActiveAllocations);
|
|
Separator();
|
|
|
|
enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count };
|
|
const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" };
|
|
enum { 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 };
|
|
const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
|
|
if (cfg->ShowWindowsRectsType < 0)
|
|
cfg->ShowWindowsRectsType = WRT_WorkRect;
|
|
if (cfg->ShowTablesRectsType < 0)
|
|
cfg->ShowTablesRectsType = TRT_WorkRect;
|
|
|
|
struct Funcs
|
|
{
|
|
static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
|
|
{
|
|
if (rect_type == TRT_OuterRect) { return table->OuterRect; }
|
|
else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
|
|
else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
|
|
else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
|
|
else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
|
|
else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }
|
|
else 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->LastOuterHeight); }
|
|
else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
|
|
else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
|
|
else 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->LastFirstRowHeight); }
|
|
else 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->LastFirstRowHeight); }
|
|
else 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->LastFirstRowHeight); }
|
|
else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
|
|
IM_ASSERT(0);
|
|
return ImRect();
|
|
}
|
|
|
|
static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
|
|
{
|
|
if (rect_type == WRT_OuterRect) { return window->Rect(); }
|
|
else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }
|
|
else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
|
|
else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
|
|
else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
|
|
else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
|
|
else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); }
|
|
else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; }
|
|
IM_ASSERT(0);
|
|
return ImRect();
|
|
}
|
|
};
|
|
|
|
if (TreeNode("Tools"))
|
|
{
|
|
if (Button("Item Picker.."))
|
|
DebugStartItemPicker();
|
|
SameLine();
|
|
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
|
|
|
|
Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
|
|
Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
|
|
SameLine();
|
|
SetNextItemWidth(GetFontSize() * 12);
|
|
cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count);
|
|
if (cfg->ShowWindowsRects && g.NavWindow != NULL)
|
|
{
|
|
BulletText("'%s':", g.NavWindow->Name);
|
|
Indent();
|
|
for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
|
|
{
|
|
ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
|
|
Text("(%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]);
|
|
}
|
|
Unindent();
|
|
}
|
|
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
|
|
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
|
|
|
|
Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
|
|
SameLine();
|
|
SetNextItemWidth(GetFontSize() * 12);
|
|
cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
|
|
if (cfg->ShowTablesRects && g.NavWindow != NULL)
|
|
{
|
|
for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
|
|
{
|
|
ImGuiTable* table = g.Tables.GetByIndex(table_n);
|
|
if (table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
|
|
continue;
|
|
|
|
BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
|
|
if (IsItemHovered())
|
|
GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f);
|
|
Indent();
|
|
char buf[128];
|
|
for (int rect_n = 0; rect_n < TRT_Count; rect_n++)
|
|
{
|
|
if (rect_n >= TRT_ColumnsRect)
|
|
{
|
|
if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect)
|
|
continue;
|
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
|
{
|
|
ImRect r = Funcs::GetTableRect(table, rect_n, column_n);
|
|
ImFormatString(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]);
|
|
Selectable(buf);
|
|
if (IsItemHovered())
|
|
GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ImRect r = Funcs::GetTableRect(table, rect_n, -1);
|
|
ImFormatString(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]);
|
|
Selectable(buf);
|
|
if (IsItemHovered())
|
|
GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f);
|
|
}
|
|
}
|
|
Unindent();
|
|
}
|
|
}
|
|
|
|
TreePop();
|
|
}
|
|
|
|
DebugNodeWindowsList(&g.Windows, "Windows");
|
|
if (TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
|
|
{
|
|
for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
|
|
DebugNodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
|
|
TreePop();
|
|
}
|
|
|
|
if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
|
|
{
|
|
for (int i = 0; i < g.OpenPopupStack.Size; i++)
|
|
{
|
|
ImGuiWindow* window = g.OpenPopupStack[i].Window;
|
|
BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
|
|
}
|
|
TreePop();
|
|
}
|
|
|
|
if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
|
|
{
|
|
for (int n = 0; n < g.TabBars.GetSize(); n++)
|
|
DebugNodeTabBar(g.TabBars.GetByIndex(n), "TabBar");
|
|
TreePop();
|
|
}
|
|
|
|
#ifdef IMGUI_HAS_TABLE
|
|
if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
|
|
{
|
|
for (int n = 0; n < g.Tables.GetSize(); n++)
|
|
DebugNodeTable(g.Tables.GetByIndex(n));
|
|
TreePop();
|
|
}
|
|
#endif
|
|
|
|
#ifdef IMGUI_HAS_DOCK
|
|
if (TreeNode("Docking"))
|
|
{
|
|
TreePop();
|
|
}
|
|
#endif
|
|
|
|
if (TreeNode("Settings"))
|
|
{
|
|
if (SmallButton("Clear"))
|
|
ClearIniSettings();
|
|
SameLine();
|
|
if (SmallButton("Save to memory"))
|
|
SaveIniSettingsToMemory();
|
|
SameLine();
|
|
if (SmallButton("Save to disk"))
|
|
SaveIniSettingsToDisk(g.IO.IniFilename);
|
|
SameLine();
|
|
if (g.IO.IniFilename)
|
|
Text("\"%s\"", g.IO.IniFilename);
|
|
else
|
|
TextUnformatted("<NULL>");
|
|
Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
|
|
if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
|
|
{
|
|
for (int n = 0; n < g.SettingsHandlers.Size; n++)
|
|
BulletText("%s", g.SettingsHandlers[n].TypeName);
|
|
TreePop();
|
|
}
|
|
if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
|
|
{
|
|
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
|
|
DebugNodeWindowSettings(settings);
|
|
TreePop();
|
|
}
|
|
|
|
#ifdef IMGUI_HAS_TABLE
|
|
if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
|
|
{
|
|
for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
|
|
DebugNodeTableSettings(settings);
|
|
TreePop();
|
|
}
|
|
#endif
|
|
|
|
#ifdef IMGUI_HAS_DOCK
|
|
#endif
|
|
|
|
if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
|
|
{
|
|
InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly);
|
|
TreePop();
|
|
}
|
|
TreePop();
|
|
}
|
|
|
|
if (TreeNode("Internal state"))
|
|
{
|
|
const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
|
|
|
|
Text("WINDOWING");
|
|
Indent();
|
|
Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
|
|
Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
|
|
Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
|
|
Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
|
|
Unindent();
|
|
|
|
Text("ITEMS");
|
|
Indent();
|
|
Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]);
|
|
Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
|
|
Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap);
|
|
Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
|
|
Unindent();
|
|
|
|
Text("NAV,FOCUS");
|
|
Indent();
|
|
Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
|
|
Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
|
|
Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
|
|
Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
|
|
Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
|
|
Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
|
|
Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
|
|
Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
|
|
Unindent();
|
|
|
|
TreePop();
|
|
}
|
|
|
|
if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
|
|
{
|
|
for (int n = 0; n < g.Windows.Size; n++)
|
|
{
|
|
ImGuiWindow* window = g.Windows[n];
|
|
if (!window->WasActive)
|
|
continue;
|
|
ImDrawList* draw_list = GetForegroundDrawList(window);
|
|
if (cfg->ShowWindowsRects)
|
|
{
|
|
ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType);
|
|
draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
|
|
}
|
|
if (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
{
|
|
char buf[32];
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
|
|
float font_size = GetFontSize();
|
|
draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
|
|
draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef IMGUI_HAS_TABLE
|
|
if (cfg->ShowTablesRects)
|
|
{
|
|
for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
|
|
{
|
|
ImGuiTable* table = g.Tables.GetByIndex(table_n);
|
|
if (table->LastFrameActive < g.FrameCount - 1)
|
|
continue;
|
|
ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
|
|
if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
|
|
{
|
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
|
{
|
|
ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);
|
|
ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);
|
|
float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;
|
|
draw_list->AddRect(r.Min, r.Max, col, 0.0f, ~0, thickness);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1);
|
|
draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef IMGUI_HAS_DOCK
|
|
if (show_docking_nodes && g.IO.KeyCtrl)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
End();
|
|
}
|
|
|
|
void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
|
|
{
|
|
if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
|
|
return;
|
|
BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
|
|
for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
|
|
BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
|
|
TreePop();
|
|
}
|
|
|
|
void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label)
|
|
{
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
|
|
int cmd_count = draw_list->CmdBuffer.Size;
|
|
if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL)
|
|
cmd_count--;
|
|
bool 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);
|
|
if (draw_list == GetWindowDrawList())
|
|
{
|
|
SameLine();
|
|
TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING");
|
|
if (node_open)
|
|
TreePop();
|
|
return;
|
|
}
|
|
|
|
ImDrawList* fg_draw_list = GetForegroundDrawList(window);
|
|
if (window && IsItemHovered())
|
|
fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
|
|
if (!node_open)
|
|
return;
|
|
|
|
if (window && !window->WasActive)
|
|
TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
|
|
|
|
for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++)
|
|
{
|
|
if (pcmd->UserCallback)
|
|
{
|
|
BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
|
|
continue;
|
|
}
|
|
|
|
char buf[300];
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
|
|
pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,
|
|
pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
|
|
bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
|
|
if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list)
|
|
DebugNodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes);
|
|
if (!pcmd_node_open)
|
|
continue;
|
|
|
|
const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
|
|
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset;
|
|
float total_area = 0.0f;
|
|
for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; )
|
|
{
|
|
ImVec2 triangle[3];
|
|
for (int n = 0; n < 3; n++, idx_n++)
|
|
triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos;
|
|
total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
|
|
}
|
|
|
|
ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
|
|
Selectable(buf);
|
|
if (IsItemHovered() && fg_draw_list)
|
|
DebugNodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, true, false);
|
|
|
|
ImGuiListClipper clipper;
|
|
clipper.Begin(pcmd->ElemCount / 3);
|
|
while (clipper.Step())
|
|
for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
|
|
{
|
|
char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf);
|
|
ImVec2 triangle[3];
|
|
for (int n = 0; n < 3; n++, idx_i++)
|
|
{
|
|
const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
|
|
triangle[n] = v.pos;
|
|
buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
|
|
(n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
|
|
}
|
|
|
|
Selectable(buf, false);
|
|
if (fg_draw_list && IsItemHovered())
|
|
{
|
|
ImDrawListFlags backup_flags = fg_draw_list->Flags;
|
|
fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines;
|
|
fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f);
|
|
fg_draw_list->Flags = backup_flags;
|
|
}
|
|
}
|
|
TreePop();
|
|
}
|
|
TreePop();
|
|
}
|
|
|
|
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)
|
|
{
|
|
IM_ASSERT(show_mesh || show_aabb);
|
|
ImDrawList* fg_draw_list = GetForegroundDrawList(window);
|
|
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
|
|
ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
|
|
|
|
ImRect clip_rect = draw_cmd->ClipRect;
|
|
ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
ImDrawListFlags backup_flags = fg_draw_list->Flags;
|
|
fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines;
|
|
for (unsigned int idx_n = draw_cmd->IdxOffset; idx_n < draw_cmd->IdxOffset + draw_cmd->ElemCount; )
|
|
{
|
|
ImVec2 triangle[3];
|
|
for (int n = 0; n < 3; n++, idx_n++)
|
|
vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
|
|
if (show_mesh)
|
|
fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f);
|
|
}
|
|
if (show_aabb)
|
|
{
|
|
fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255));
|
|
fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255));
|
|
}
|
|
fg_draw_list->Flags = backup_flags;
|
|
}
|
|
|
|
void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
|
|
{
|
|
if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
|
|
return;
|
|
for (int n = 0; n < storage->Data.Size; n++)
|
|
{
|
|
const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
|
|
BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i);
|
|
}
|
|
TreePop();
|
|
}
|
|
|
|
void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
|
|
{
|
|
char buf[256];
|
|
char* p = buf;
|
|
const char* buf_end = buf + IM_ARRAYSIZE(buf);
|
|
const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2);
|
|
p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
|
|
IM_UNUSED(p);
|
|
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
|
bool open = TreeNode(tab_bar, "%s", buf);
|
|
if (!is_active) { PopStyleColor(); }
|
|
if (is_active && IsItemHovered())
|
|
{
|
|
ImDrawList* draw_list = GetForegroundDrawList();
|
|
draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
|
|
draw_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));
|
|
draw_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));
|
|
}
|
|
if (open)
|
|
{
|
|
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
|
{
|
|
const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
|
PushID(tab);
|
|
if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
|
|
if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
|
|
Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f",
|
|
tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth);
|
|
PopID();
|
|
}
|
|
TreePop();
|
|
}
|
|
}
|
|
|
|
void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
|
|
{
|
|
if (window == NULL)
|
|
{
|
|
BulletText("%s: NULL", label);
|
|
return;
|
|
}
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
const bool is_active = window->WasActive;
|
|
ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;
|
|
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
|
const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
|
|
if (!is_active) { PopStyleColor(); }
|
|
if (IsItemHovered() && is_active)
|
|
GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
|
|
if (!open)
|
|
return;
|
|
|
|
if (window->MemoryCompacted)
|
|
TextDisabled("Note: some memory buffers have been compacted/freed.");
|
|
|
|
ImGuiWindowFlags flags = window->Flags;
|
|
DebugNodeDrawList(window, window->DrawList, "DrawList");
|
|
BulletText("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);
|
|
BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
|
|
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
|
|
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
|
|
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
|
|
BulletText("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" : "");
|
|
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
|
|
BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
|
|
BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
|
|
BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
|
|
if (!window->NavRectRel[0].IsInverted())
|
|
BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
|
|
else
|
|
BulletText("NavRectRel[0]: <None>");
|
|
if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
|
|
if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
|
|
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
|
|
if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
|
|
{
|
|
for (int n = 0; n < window->ColumnsStorage.Size; n++)
|
|
DebugNodeColumns(&window->ColumnsStorage[n]);
|
|
TreePop();
|
|
}
|
|
DebugNodeStorage(&window->StateStorage, "Storage");
|
|
TreePop();
|
|
}
|
|
|
|
void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings)
|
|
{
|
|
Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
|
|
settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
|
|
}
|
|
|
|
|
|
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label)
|
|
{
|
|
if (!TreeNode(label, "%s (%d)", label, windows->Size))
|
|
return;
|
|
Text("(In front-to-back order:)");
|
|
for (int i = windows->Size - 1; i >= 0; i--)
|
|
{
|
|
PushID((*windows)[i]);
|
|
DebugNodeWindow((*windows)[i], "Window");
|
|
PopID();
|
|
}
|
|
TreePop();
|
|
}
|
|
|
|
#else
|
|
|
|
void ImGui::ShowMetricsWindow(bool*) {}
|
|
void ImGui::DebugNodeColumns(ImGuiOldColumns*) {}
|
|
void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {}
|
|
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
|
|
void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
|
|
void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
|
|
void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
|
|
void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
|
|
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}
|
|
|
|
#endif
|
|
|
|
#ifdef IMGUI_INCLUDE_IMGUI_USER_INL
|
|
#include "imgui_user.inl"
|
|
#endif
|
|
|
|
#endif
|