mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-26 16:04:34 +00:00
Update imgui to 1.67. Also update imguicolortextedit.
This commit is contained in:
parent
32f0a27d3b
commit
ac791fd19f
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2018 Omar Cornut
|
Copyright (c) 2014-2019 Omar Cornut
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
//---- Don't implement some functions to reduce linkage requirements.
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
|
||||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function.
|
||||||
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
|
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
|
||||||
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
|
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
|
||||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
1185
imgui/imgui.cpp
1185
imgui/imgui.cpp
File diff suppressed because it is too large
Load Diff
844
imgui/imgui.h
844
imgui/imgui.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
// dear imgui, v1.65
|
// dear imgui, v1.67
|
||||||
// (drawing and font code)
|
// (drawing and font code)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -12,7 +12,8 @@ Index of this file:
|
|||||||
// [SECTION] Helpers ShadeVertsXXX functions
|
// [SECTION] Helpers ShadeVertsXXX functions
|
||||||
// [SECTION] ImFontConfig
|
// [SECTION] ImFontConfig
|
||||||
// [SECTION] ImFontAtlas
|
// [SECTION] ImFontAtlas
|
||||||
// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
|
// [SECTION] ImFontAtlas glyph ranges helpers
|
||||||
|
// [SECTION] ImFontGlyphRangesBuilder
|
||||||
// [SECTION] ImFont
|
// [SECTION] ImFont
|
||||||
// [SECTION] Internal Render Helpers
|
// [SECTION] Internal Render Helpers
|
||||||
// [SECTION] Decompression code
|
// [SECTION] Decompression code
|
||||||
@ -32,7 +33,7 @@ Index of this file:
|
|||||||
|
|
||||||
#include <stdio.h> // vsnprintf, sscanf, printf
|
#include <stdio.h> // vsnprintf, sscanf, printf
|
||||||
#if !defined(alloca)
|
#if !defined(alloca)
|
||||||
#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__)
|
#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__)
|
||||||
#include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
|
#include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include <malloc.h> // alloca
|
#include <malloc.h> // alloca
|
||||||
@ -56,6 +57,7 @@ Index of this file:
|
|||||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
|
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
|
||||||
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
|
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
|
||||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
|
||||||
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
|
||||||
#if __has_warning("-Wcomma")
|
#if __has_warning("-Wcomma")
|
||||||
#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
|
#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
|
||||||
#endif
|
#endif
|
||||||
@ -63,7 +65,7 @@ Index of this file:
|
|||||||
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
|
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
|
||||||
#endif
|
#endif
|
||||||
#if __has_warning("-Wdouble-promotion")
|
#if __has_warning("-Wdouble-promotion")
|
||||||
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
|
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||||
@ -175,7 +177,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|||||||
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||||
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
|
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
|
||||||
colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
|
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
|
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
@ -205,6 +207,11 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
|
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||||
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||||
|
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||||
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||||
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||||
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||||
@ -255,6 +262,11 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
|
|||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
|
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
|
||||||
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||||
|
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||||
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||||
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||||
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||||
@ -306,6 +318,11 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
|||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
|
colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||||
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
|
||||||
|
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||||
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||||
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||||
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
|
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||||
@ -640,7 +657,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
|
|||||||
_IdxWritePtr += 6;
|
_IdxWritePtr += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds.
|
||||||
|
// Those macros expects l-values.
|
||||||
|
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } }
|
||||||
|
#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } }
|
||||||
|
|
||||||
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
||||||
|
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||||
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
|
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
|
||||||
{
|
{
|
||||||
if (points_count < 2)
|
if (points_count < 2)
|
||||||
@ -670,10 +693,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|||||||
for (int i1 = 0; i1 < count; i1++)
|
for (int i1 = 0; i1 < count; i1++)
|
||||||
{
|
{
|
||||||
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
||||||
ImVec2 diff = points[i2] - points[i1];
|
float dx = points[i2].x - points[i1].x;
|
||||||
diff *= ImInvLength(diff, 1.0f);
|
float dy = points[i2].y - points[i1].y;
|
||||||
temp_normals[i1].x = diff.y;
|
IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
||||||
temp_normals[i1].y = -diff.x;
|
temp_normals[i1].x = dy;
|
||||||
|
temp_normals[i1].y = -dx;
|
||||||
}
|
}
|
||||||
if (!closed)
|
if (!closed)
|
||||||
temp_normals[points_count-1] = temp_normals[points_count-2];
|
temp_normals[points_count-1] = temp_normals[points_count-2];
|
||||||
@ -696,17 +720,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|||||||
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
|
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
|
||||||
|
|
||||||
// Average normals
|
// Average normals
|
||||||
ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
|
float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
|
||||||
float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
|
||||||
if (dmr2 > 0.000001f)
|
IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f)
|
||||||
{
|
dm_x *= AA_SIZE;
|
||||||
float scale = 1.0f / dmr2;
|
dm_y *= AA_SIZE;
|
||||||
if (scale > 100.0f) scale = 100.0f;
|
|
||||||
dm *= scale;
|
// Add temporary vertexes
|
||||||
}
|
ImVec2* out_vtx = &temp_points[i2*2];
|
||||||
dm *= AA_SIZE;
|
out_vtx[0].x = points[i2].x + dm_x;
|
||||||
temp_points[i2*2+0] = points[i2] + dm;
|
out_vtx[0].y = points[i2].y + dm_y;
|
||||||
temp_points[i2*2+1] = points[i2] - dm;
|
out_vtx[1].x = points[i2].x - dm_x;
|
||||||
|
out_vtx[1].y = points[i2].y - dm_y;
|
||||||
|
|
||||||
// Add indexes
|
// Add indexes
|
||||||
_IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
_IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
||||||
@ -750,20 +775,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|||||||
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
|
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
|
||||||
|
|
||||||
// Average normals
|
// Average normals
|
||||||
ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
|
float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
|
||||||
float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
|
||||||
if (dmr2 > 0.000001f)
|
IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
|
||||||
{
|
float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
|
||||||
float scale = 1.0f / dmr2;
|
float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
|
||||||
if (scale > 100.0f) scale = 100.0f;
|
float dm_in_x = dm_x * half_inner_thickness;
|
||||||
dm *= scale;
|
float dm_in_y = dm_y * half_inner_thickness;
|
||||||
}
|
|
||||||
ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
|
// Add temporary vertexes
|
||||||
ImVec2 dm_in = dm * half_inner_thickness;
|
ImVec2* out_vtx = &temp_points[i2*4];
|
||||||
temp_points[i2*4+0] = points[i2] + dm_out;
|
out_vtx[0].x = points[i2].x + dm_out_x;
|
||||||
temp_points[i2*4+1] = points[i2] + dm_in;
|
out_vtx[0].y = points[i2].y + dm_out_y;
|
||||||
temp_points[i2*4+2] = points[i2] - dm_in;
|
out_vtx[1].x = points[i2].x + dm_in_x;
|
||||||
temp_points[i2*4+3] = points[i2] - dm_out;
|
out_vtx[1].y = points[i2].y + dm_in_y;
|
||||||
|
out_vtx[2].x = points[i2].x - dm_in_x;
|
||||||
|
out_vtx[2].y = points[i2].y - dm_in_y;
|
||||||
|
out_vtx[3].x = points[i2].x - dm_out_x;
|
||||||
|
out_vtx[3].y = points[i2].y - dm_out_y;
|
||||||
|
|
||||||
// Add indexes
|
// Add indexes
|
||||||
_IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
_IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
||||||
@ -801,11 +830,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|||||||
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
||||||
const ImVec2& p1 = points[i1];
|
const ImVec2& p1 = points[i1];
|
||||||
const ImVec2& p2 = points[i2];
|
const ImVec2& p2 = points[i2];
|
||||||
ImVec2 diff = p2 - p1;
|
|
||||||
diff *= ImInvLength(diff, 1.0f);
|
|
||||||
|
|
||||||
const float dx = diff.x * (thickness * 0.5f);
|
float dx = p2.x - p1.x;
|
||||||
const float dy = diff.y * (thickness * 0.5f);
|
float dy = p2.y - p1.y;
|
||||||
|
IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
||||||
|
dx *= (thickness * 0.5f);
|
||||||
|
dy *= (thickness * 0.5f);
|
||||||
|
|
||||||
_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
|
_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
|
||||||
_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
|
_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
|
||||||
_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
|
_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
|
||||||
@ -820,8 +851,12 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||||
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
||||||
{
|
{
|
||||||
|
if (points_count < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
const ImVec2 uv = _Data->TexUvWhitePixel;
|
const ImVec2 uv = _Data->TexUvWhitePixel;
|
||||||
|
|
||||||
if (Flags & ImDrawListFlags_AntiAliasedFill)
|
if (Flags & ImDrawListFlags_AntiAliasedFill)
|
||||||
@ -848,10 +883,11 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
|
|||||||
{
|
{
|
||||||
const ImVec2& p0 = points[i0];
|
const ImVec2& p0 = points[i0];
|
||||||
const ImVec2& p1 = points[i1];
|
const ImVec2& p1 = points[i1];
|
||||||
ImVec2 diff = p1 - p0;
|
float dx = p1.x - p0.x;
|
||||||
diff *= ImInvLength(diff, 1.0f);
|
float dy = p1.y - p0.y;
|
||||||
temp_normals[i0].x = diff.y;
|
IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
||||||
temp_normals[i0].y = -diff.x;
|
temp_normals[i0].x = dy;
|
||||||
|
temp_normals[i0].y = -dx;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
|
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
|
||||||
@ -859,19 +895,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
|
|||||||
// Average normals
|
// Average normals
|
||||||
const ImVec2& n0 = temp_normals[i0];
|
const ImVec2& n0 = temp_normals[i0];
|
||||||
const ImVec2& n1 = temp_normals[i1];
|
const ImVec2& n1 = temp_normals[i1];
|
||||||
ImVec2 dm = (n0 + n1) * 0.5f;
|
float dm_x = (n0.x + n1.x) * 0.5f;
|
||||||
float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
float dm_y = (n0.y + n1.y) * 0.5f;
|
||||||
if (dmr2 > 0.000001f)
|
IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
|
||||||
{
|
dm_x *= AA_SIZE * 0.5f;
|
||||||
float scale = 1.0f / dmr2;
|
dm_y *= AA_SIZE * 0.5f;
|
||||||
if (scale > 100.0f) scale = 100.0f;
|
|
||||||
dm *= scale;
|
|
||||||
}
|
|
||||||
dm *= AA_SIZE * 0.5f;
|
|
||||||
|
|
||||||
// Add vertices
|
// Add vertices
|
||||||
_VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
|
_VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
|
||||||
_VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
|
_VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
|
||||||
_VtxWritePtr += 2;
|
_VtxWritePtr += 2;
|
||||||
|
|
||||||
// Add indexes for fringes
|
// Add indexes for fringes
|
||||||
@ -1392,7 +1424,7 @@ ImFontAtlas::ImFontAtlas()
|
|||||||
{
|
{
|
||||||
Locked = false;
|
Locked = false;
|
||||||
Flags = ImFontAtlasFlags_None;
|
Flags = ImFontAtlasFlags_None;
|
||||||
TexID = NULL;
|
TexID = (ImTextureID)NULL;
|
||||||
TexDesiredWidth = 0;
|
TexDesiredWidth = 0;
|
||||||
TexGlyphPadding = 1;
|
TexGlyphPadding = 1;
|
||||||
|
|
||||||
@ -1510,11 +1542,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
|||||||
if (!font_cfg->MergeMode)
|
if (!font_cfg->MergeMode)
|
||||||
Fonts.push_back(IM_NEW(ImFont));
|
Fonts.push_back(IM_NEW(ImFont));
|
||||||
else
|
else
|
||||||
IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
||||||
|
|
||||||
ConfigData.push_back(*font_cfg);
|
ConfigData.push_back(*font_cfg);
|
||||||
ImFontConfig& new_font_cfg = ConfigData.back();
|
ImFontConfig& new_font_cfg = ConfigData.back();
|
||||||
if (!new_font_cfg.DstFont)
|
if (new_font_cfg.DstFont == NULL)
|
||||||
new_font_cfg.DstFont = Fonts.back();
|
new_font_cfg.DstFont = Fonts.back();
|
||||||
if (!new_font_cfg.FontDataOwnedByAtlas)
|
if (!new_font_cfg.FontDataOwnedByAtlas)
|
||||||
{
|
{
|
||||||
@ -1702,139 +1734,220 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
|
|||||||
data[i] = table[data[i]];
|
data[i] = table[data[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
|
||||||
|
// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
|
||||||
|
struct ImFontBuildSrcData
|
||||||
|
{
|
||||||
|
stbtt_fontinfo FontInfo;
|
||||||
|
stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
|
||||||
|
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
||||||
|
stbtt_packedchar* PackedChars; // Output glyphs
|
||||||
|
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
||||||
|
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
||||||
|
int GlyphsHighest; // Highest requested codepoint
|
||||||
|
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
||||||
|
ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
||||||
|
ImVector<int> GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
||||||
|
struct ImFontBuildDstData
|
||||||
|
{
|
||||||
|
int SrcCount; // Number of source fonts targeting this destination font.
|
||||||
|
int GlyphsHighest;
|
||||||
|
int GlyphsCount;
|
||||||
|
ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
||||||
|
};
|
||||||
|
|
||||||
|
static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector<int>* out)
|
||||||
|
{
|
||||||
|
IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
|
||||||
|
const int* it_begin = in->Storage.begin();
|
||||||
|
const int* it_end = in->Storage.end();
|
||||||
|
for (const int* it = it_begin; it < it_end; it++)
|
||||||
|
if (int entries_32 = *it)
|
||||||
|
for (int bit_n = 0; bit_n < 32; bit_n++)
|
||||||
|
if (entries_32 & (1 << bit_n))
|
||||||
|
out->push_back((int)((it - it_begin) << 5) + bit_n);
|
||||||
|
}
|
||||||
|
|
||||||
bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||||
{
|
{
|
||||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||||
|
|
||||||
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
||||||
|
|
||||||
atlas->TexID = NULL;
|
// Clear atlas
|
||||||
|
atlas->TexID = (ImTextureID)NULL;
|
||||||
atlas->TexWidth = atlas->TexHeight = 0;
|
atlas->TexWidth = atlas->TexHeight = 0;
|
||||||
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||||
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||||
atlas->ClearTexData();
|
atlas->ClearTexData();
|
||||||
|
|
||||||
// Count glyphs/ranges
|
// Temporary storage for building
|
||||||
int total_glyphs_count = 0;
|
ImVector<ImFontBuildSrcData> src_tmp_array;
|
||||||
int total_ranges_count = 0;
|
ImVector<ImFontBuildDstData> dst_tmp_array;
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||||
|
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||||
|
memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||||
|
memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||||
|
|
||||||
|
// 1. Initialize font loading structure, check font data validity
|
||||||
|
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
if (!cfg.GlyphRanges)
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
|
|
||||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
|
|
||||||
total_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
|
|
||||||
// Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
|
||||||
atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
|
|
||||||
atlas->TexHeight = 0;
|
|
||||||
|
|
||||||
// Start packing
|
|
||||||
const int max_tex_height = 1024*32;
|
|
||||||
stbtt_pack_context spc = {};
|
|
||||||
if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
|
|
||||||
return false;
|
|
||||||
stbtt_PackSetOversampling(&spc, 1, 1);
|
|
||||||
|
|
||||||
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
|
||||||
ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
|
|
||||||
|
|
||||||
// Initialize font information (so we can error without any cleanup)
|
|
||||||
struct ImFontTempBuildData
|
|
||||||
{
|
|
||||||
stbtt_fontinfo FontInfo;
|
|
||||||
stbrp_rect* Rects;
|
|
||||||
int RectsCount;
|
|
||||||
stbtt_pack_range* Ranges;
|
|
||||||
int RangesCount;
|
|
||||||
};
|
|
||||||
ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
|
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
||||||
{
|
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
||||||
ImFontTempBuildData& tmp = tmp_array[input_i];
|
|
||||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||||
|
|
||||||
|
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||||
|
src_tmp.DstIndex = -1;
|
||||||
|
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||||
|
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||||
|
src_tmp.DstIndex = output_i;
|
||||||
|
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||||
|
if (src_tmp.DstIndex == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Initialize helper structure for font loading and verify that the TTF/OTF data is correct
|
||||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
||||||
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
||||||
if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
||||||
{
|
|
||||||
atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
|
|
||||||
ImGui::MemFree(tmp_array);
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Measure highest codepoints
|
||||||
|
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||||
|
dst_tmp.SrcCount++;
|
||||||
|
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
||||||
|
int total_glyphs_count = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
|
||||||
|
if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
|
||||||
|
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
|
||||||
|
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
|
||||||
|
{
|
||||||
|
if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
||||||
|
continue;
|
||||||
|
if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font?
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add to avail set/counters
|
||||||
|
src_tmp.GlyphsCount++;
|
||||||
|
dst_tmp.GlyphsCount++;
|
||||||
|
src_tmp.GlyphsSet.SetBit(codepoint, true);
|
||||||
|
if (dst_tmp.SrcCount > 1)
|
||||||
|
dst_tmp.GlyphsSet.SetBit(codepoint, true);
|
||||||
|
total_glyphs_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
|
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
||||||
|
UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
|
||||||
|
src_tmp.GlyphsSet.Clear();
|
||||||
|
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
||||||
|
}
|
||||||
|
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
||||||
|
dst_tmp_array[dst_i].GlyphsSet.Clear();
|
||||||
|
dst_tmp_array.clear();
|
||||||
|
|
||||||
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
||||||
int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
|
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
||||||
stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
|
ImVector<stbrp_rect> buf_rects;
|
||||||
stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
|
ImVector<stbtt_packedchar> buf_packedchars;
|
||||||
stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
|
buf_rects.resize(total_glyphs_count);
|
||||||
memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
|
buf_packedchars.resize(total_glyphs_count);
|
||||||
memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
|
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
||||||
memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
|
memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
|
||||||
|
|
||||||
// First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
|
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
int total_surface = 0;
|
||||||
|
int buf_rects_out_n = 0;
|
||||||
|
int buf_packedchars_out_n = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
ImFontTempBuildData& tmp = tmp_array[input_i];
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Setup ranges
|
src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
||||||
int font_glyphs_count = 0;
|
src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
|
||||||
int font_ranges_count = 0;
|
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
|
buf_packedchars_out_n += src_tmp.GlyphsCount;
|
||||||
font_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
|
||||||
tmp.Ranges = buf_ranges + buf_ranges_n;
|
// Convert our ranges in the format stb_truetype wants
|
||||||
tmp.RangesCount = font_ranges_count;
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
buf_ranges_n += font_ranges_count;
|
src_tmp.PackRange.font_size = cfg.SizePixels;
|
||||||
for (int i = 0; i < font_ranges_count; i++)
|
src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
|
||||||
|
src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
|
||||||
|
src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
|
||||||
|
src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
|
||||||
|
src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
|
||||||
|
src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
|
||||||
|
|
||||||
|
// Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
|
||||||
|
const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
|
||||||
|
const int padding = atlas->TexGlyphPadding;
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||||
{
|
{
|
||||||
const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
|
int x0, y0, x1, y1;
|
||||||
stbtt_pack_range& range = tmp.Ranges[i];
|
const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
|
||||||
range.font_size = cfg.SizePixels;
|
IM_ASSERT(glyph_index_in_font != 0);
|
||||||
range.first_unicode_codepoint_in_range = in_range[0];
|
stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
|
||||||
range.num_chars = (in_range[1] - in_range[0]) + 1;
|
src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
|
||||||
range.chardata_for_range = buf_packedchars + buf_packedchars_n;
|
src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
|
||||||
buf_packedchars_n += range.num_chars;
|
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||||
}
|
|
||||||
|
|
||||||
// Gather the sizes of all rectangle we need
|
|
||||||
tmp.Rects = buf_rects + buf_rects_n;
|
|
||||||
tmp.RectsCount = font_glyphs_count;
|
|
||||||
buf_rects_n += font_glyphs_count;
|
|
||||||
stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
|
|
||||||
int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
|
|
||||||
IM_ASSERT(n == font_glyphs_count);
|
|
||||||
|
|
||||||
// Detect missing glyphs and replace them with a zero-sized box instead of relying on the default glyphs
|
|
||||||
// This allows us merging overlapping icon fonts more easily.
|
|
||||||
int rect_i = 0;
|
|
||||||
for (int range_i = 0; range_i < tmp.RangesCount; range_i++)
|
|
||||||
for (int char_i = 0; char_i < tmp.Ranges[range_i].num_chars; char_i++, rect_i++)
|
|
||||||
if (stbtt_FindGlyphIndex(&tmp.FontInfo, tmp.Ranges[range_i].first_unicode_codepoint_in_range + char_i) == 0)
|
|
||||||
tmp.Rects[rect_i].w = tmp.Rects[rect_i].h = 0;
|
|
||||||
|
|
||||||
// Pack
|
|
||||||
stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
|
|
||||||
|
|
||||||
// Extend texture height
|
|
||||||
// Also mark missing glyphs as non-packed so we don't attempt to render into them
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
if (tmp.Rects[i].w == 0 && tmp.Rects[i].h == 0)
|
|
||||||
tmp.Rects[i].was_packed = 0;
|
|
||||||
if (tmp.Rects[i].was_packed)
|
|
||||||
atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IM_ASSERT(buf_rects_n == total_glyphs_count);
|
|
||||||
IM_ASSERT(buf_packedchars_n == total_glyphs_count);
|
|
||||||
IM_ASSERT(buf_ranges_n == total_ranges_count);
|
|
||||||
|
|
||||||
// Create texture
|
// We need a width for the skyline algorithm, any width!
|
||||||
|
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||||
|
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
||||||
|
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
||||||
|
atlas->TexHeight = 0;
|
||||||
|
if (atlas->TexDesiredWidth > 0)
|
||||||
|
atlas->TexWidth = atlas->TexDesiredWidth;
|
||||||
|
else
|
||||||
|
atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
|
||||||
|
|
||||||
|
// 5. Start packing
|
||||||
|
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||||
|
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||||
|
stbtt_pack_context spc = {};
|
||||||
|
stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
|
||||||
|
ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
|
||||||
|
|
||||||
|
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
||||||
|
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
if (src_tmp.Rects[glyph_i].was_packed)
|
||||||
|
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Allocate texture
|
||||||
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
||||||
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||||
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
||||||
@ -1842,41 +1955,46 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|||||||
spc.pixels = atlas->TexPixelsAlpha8;
|
spc.pixels = atlas->TexPixelsAlpha8;
|
||||||
spc.height = atlas->TexHeight;
|
spc.height = atlas->TexHeight;
|
||||||
|
|
||||||
// Second pass: render font characters
|
// 8. Render/rasterize font characters into the texture
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
ImFontTempBuildData& tmp = tmp_array[input_i];
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
|
if (src_tmp.GlyphsCount == 0)
|
||||||
stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
|
continue;
|
||||||
|
|
||||||
|
stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
|
||||||
|
|
||||||
|
// Apply multiply operator
|
||||||
if (cfg.RasterizerMultiply != 1.0f)
|
if (cfg.RasterizerMultiply != 1.0f)
|
||||||
{
|
{
|
||||||
unsigned char multiply_table[256];
|
unsigned char multiply_table[256];
|
||||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||||
for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
|
stbrp_rect* r = &src_tmp.Rects[0];
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
|
||||||
if (r->was_packed)
|
if (r->was_packed)
|
||||||
ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
|
ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
|
||||||
}
|
}
|
||||||
tmp.Rects = NULL;
|
src_tmp.Rects = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End packing
|
// End packing
|
||||||
stbtt_PackEnd(&spc);
|
stbtt_PackEnd(&spc);
|
||||||
ImGui::MemFree(buf_rects);
|
buf_rects.clear();
|
||||||
buf_rects = NULL;
|
|
||||||
|
|
||||||
// Third pass: setup ImFont and glyphs for runtime
|
// 9. Setup ImFont and glyphs for runtime
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||||
ImFontTempBuildData& tmp = tmp_array[input_i];
|
if (src_tmp.GlyphsCount == 0)
|
||||||
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
|
continue;
|
||||||
if (cfg.MergeMode)
|
|
||||||
dst_font->BuildLookupTable();
|
|
||||||
|
|
||||||
const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
|
||||||
|
|
||||||
|
const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
|
||||||
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
||||||
stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
||||||
|
|
||||||
const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
||||||
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
||||||
@ -1884,40 +2002,30 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|||||||
const float font_off_x = cfg.GlyphOffset.x;
|
const float font_off_x = cfg.GlyphOffset.x;
|
||||||
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
||||||
|
|
||||||
for (int i = 0; i < tmp.RangesCount; i++)
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
{
|
{
|
||||||
stbtt_pack_range& range = tmp.Ranges[i];
|
const int codepoint = src_tmp.GlyphsList[glyph_i];
|
||||||
for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
|
const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
|
||||||
{
|
|
||||||
const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
|
|
||||||
if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
|
const float char_advance_x_org = pc.xadvance;
|
||||||
if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint))
|
const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
||||||
continue;
|
|
||||||
|
|
||||||
float char_advance_x_org = pc.xadvance;
|
|
||||||
float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
|
||||||
float char_off_x = font_off_x;
|
float char_off_x = font_off_x;
|
||||||
if (char_advance_x_org != char_advance_x_mod)
|
if (char_advance_x_org != char_advance_x_mod)
|
||||||
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
||||||
|
|
||||||
|
// Register glyph
|
||||||
stbtt_aligned_quad q;
|
stbtt_aligned_quad q;
|
||||||
float dummy_x = 0.0f, dummy_y = 0.0f;
|
float dummy_x = 0.0f, dummy_y = 0.0f;
|
||||||
stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
|
stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0);
|
||||||
dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
|
dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup temporaries
|
// Cleanup temporary (ImVector doesn't honor destructor)
|
||||||
ImGui::MemFree(buf_packedchars);
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
ImGui::MemFree(buf_ranges);
|
src_tmp_array[src_i].~ImFontBuildSrcData();
|
||||||
ImGui::MemFree(tmp_array);
|
|
||||||
|
|
||||||
ImFontAtlasBuildFinish(atlas);
|
ImFontAtlasBuildFinish(atlas);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1945,16 +2053,16 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
|
|||||||
font->ConfigDataCount++;
|
font->ConfigDataCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
|
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
|
||||||
{
|
{
|
||||||
stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
|
stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
|
||||||
|
|
||||||
ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
|
ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
|
||||||
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
|
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
|
||||||
|
|
||||||
ImVector<stbrp_rect> pack_rects;
|
ImVector<stbrp_rect> pack_rects;
|
||||||
pack_rects.resize(user_rects.Size);
|
pack_rects.resize(user_rects.Size);
|
||||||
memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
|
memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
|
||||||
for (int i = 0; i < user_rects.Size; i++)
|
for (int i = 0; i < user_rects.Size; i++)
|
||||||
{
|
{
|
||||||
pack_rects[i].w = user_rects[i].Width;
|
pack_rects[i].w = user_rects[i].Width;
|
||||||
@ -2074,7 +2182,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short*
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
|
// [SECTION] ImFontAtlas glyph ranges helpers
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
||||||
@ -2082,7 +2190,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
|||||||
// Store 2500 regularly used characters for Simplified Chinese.
|
// Store 2500 regularly used characters for Simplified Chinese.
|
||||||
// Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
|
// Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
|
||||||
// This table covers 97.97% of all characters used during the month in July, 1987.
|
// This table covers 97.97% of all characters used during the month in July, 1987.
|
||||||
// You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
// You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
||||||
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
||||||
static const short accumulative_offsets_from_0x4E00[] =
|
static const short accumulative_offsets_from_0x4E00[] =
|
||||||
{
|
{
|
||||||
@ -2148,7 +2256,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
|||||||
// 1946 common ideograms code points for Japanese
|
// 1946 common ideograms code points for Japanese
|
||||||
// Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
|
// Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
|
||||||
// FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
|
// FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
|
||||||
// You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
// You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
||||||
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
||||||
static const short accumulative_offsets_from_0x4E00[] =
|
static const short accumulative_offsets_from_0x4E00[] =
|
||||||
{
|
{
|
||||||
@ -2226,7 +2334,11 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai()
|
|||||||
return &ranges[0];
|
return &ranges[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
|
//-----------------------------------------------------------------------------
|
||||||
|
// [SECTION] ImFontGlyphRangesBuilder
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
|
||||||
{
|
{
|
||||||
while (text_end ? (text < text_end) : *text)
|
while (text_end ? (text < text_end) : *text)
|
||||||
{
|
{
|
||||||
@ -2240,14 +2352,14 @@ void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
||||||
{
|
{
|
||||||
for (; ranges[0]; ranges += 2)
|
for (; ranges[0]; ranges += 2)
|
||||||
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
|
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
|
||||||
AddChar(c);
|
AddChar(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
||||||
{
|
{
|
||||||
for (int n = 0; n < 0x10000; n++)
|
for (int n = 0; n < 0x10000; n++)
|
||||||
if (GetBit(n))
|
if (GetBit(n))
|
||||||
@ -2316,21 +2428,21 @@ void ImFont::BuildLookupTable()
|
|||||||
{
|
{
|
||||||
int codepoint = (int)Glyphs[i].Codepoint;
|
int codepoint = (int)Glyphs[i].Codepoint;
|
||||||
IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
|
IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
|
||||||
IndexLookup[codepoint] = (unsigned short)i;
|
IndexLookup[codepoint] = (ImWchar)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a glyph to handle TAB
|
// Create a glyph to handle TAB
|
||||||
// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
|
// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
|
||||||
if (FindGlyph((unsigned short)' '))
|
if (FindGlyph((ImWchar)' '))
|
||||||
{
|
{
|
||||||
if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
|
if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
|
||||||
Glyphs.resize(Glyphs.Size + 1);
|
Glyphs.resize(Glyphs.Size + 1);
|
||||||
ImFontGlyph& tab_glyph = Glyphs.back();
|
ImFontGlyph& tab_glyph = Glyphs.back();
|
||||||
tab_glyph = *FindGlyph((unsigned short)' ');
|
tab_glyph = *FindGlyph((ImWchar)' ');
|
||||||
tab_glyph.Codepoint = '\t';
|
tab_glyph.Codepoint = '\t';
|
||||||
tab_glyph.AdvanceX *= 4;
|
tab_glyph.AdvanceX *= 4;
|
||||||
IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
|
IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
|
||||||
IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1);
|
IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||||
@ -2352,7 +2464,7 @@ void ImFont::GrowIndex(int new_size)
|
|||||||
if (new_size <= IndexLookup.Size)
|
if (new_size <= IndexLookup.Size)
|
||||||
return;
|
return;
|
||||||
IndexAdvanceX.resize(new_size, -1.0f);
|
IndexAdvanceX.resize(new_size, -1.0f);
|
||||||
IndexLookup.resize(new_size, (unsigned short)-1);
|
IndexLookup.resize(new_size, (ImWchar)-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
|
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
|
||||||
@ -2385,13 +2497,13 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
|
|||||||
IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
|
IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
|
||||||
int index_size = IndexLookup.Size;
|
int index_size = IndexLookup.Size;
|
||||||
|
|
||||||
if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists
|
if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
|
||||||
return;
|
return;
|
||||||
if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
|
if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GrowIndex(dst + 1);
|
GrowIndex(dst + 1);
|
||||||
IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
|
IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;
|
||||||
IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
|
IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2399,8 +2511,8 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
|
|||||||
{
|
{
|
||||||
if (c >= IndexLookup.Size)
|
if (c >= IndexLookup.Size)
|
||||||
return FallbackGlyph;
|
return FallbackGlyph;
|
||||||
const unsigned short i = IndexLookup[c];
|
const ImWchar i = IndexLookup.Data[c];
|
||||||
if (i == (unsigned short)-1)
|
if (i == (ImWchar)-1)
|
||||||
return FallbackGlyph;
|
return FallbackGlyph;
|
||||||
return &Glyphs.Data[i];
|
return &Glyphs.Data[i];
|
||||||
}
|
}
|
||||||
@ -2409,8 +2521,8 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
|
|||||||
{
|
{
|
||||||
if (c >= IndexLookup.Size)
|
if (c >= IndexLookup.Size)
|
||||||
return NULL;
|
return NULL;
|
||||||
const unsigned short i = IndexLookup[c];
|
const ImWchar i = IndexLookup.Data[c];
|
||||||
if (i == (unsigned short)-1)
|
if (i == (ImWchar)-1)
|
||||||
return NULL;
|
return NULL;
|
||||||
return &Glyphs.Data[i];
|
return &Glyphs.Data[i];
|
||||||
}
|
}
|
||||||
@ -2469,7 +2581,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
|
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
|
||||||
if (ImCharIsBlankW(c))
|
if (ImCharIsBlankW(c))
|
||||||
{
|
{
|
||||||
if (inside_word)
|
if (inside_word)
|
||||||
@ -2586,7 +2698,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
|
const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
|
||||||
if (line_width + char_width >= max_width)
|
if (line_width + char_width >= max_width)
|
||||||
{
|
{
|
||||||
s = prev_s;
|
s = prev_s;
|
||||||
@ -2608,7 +2720,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
|||||||
return text_size;
|
return text_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const
|
void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
|
||||||
{
|
{
|
||||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
|
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
|
||||||
return;
|
return;
|
||||||
@ -2643,11 +2755,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
|||||||
// Fast-forward to first visible line
|
// Fast-forward to first visible line
|
||||||
const char* s = text_begin;
|
const char* s = text_begin;
|
||||||
if (y + line_height < clip_rect.y && !word_wrap_enabled)
|
if (y + line_height < clip_rect.y && !word_wrap_enabled)
|
||||||
while (y + line_height < clip_rect.y)
|
while (y + line_height < clip_rect.y && s < text_end)
|
||||||
{
|
{
|
||||||
while (s < text_end)
|
s = (const char*)memchr(s, '\n', text_end - s);
|
||||||
if (*s++ == '\n')
|
s = s ? s + 1 : text_end;
|
||||||
break;
|
|
||||||
y += line_height;
|
y += line_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2657,15 +2768,16 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
|||||||
{
|
{
|
||||||
const char* s_end = s;
|
const char* s_end = s;
|
||||||
float y_end = y;
|
float y_end = y;
|
||||||
while (y_end < clip_rect.w)
|
while (y_end < clip_rect.w && s_end < text_end)
|
||||||
{
|
{
|
||||||
while (s_end < text_end)
|
s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
|
||||||
if (*s_end++ == '\n')
|
s_end = s_end ? s_end + 1 : text_end;
|
||||||
break;
|
|
||||||
y_end += line_height;
|
y_end += line_height;
|
||||||
}
|
}
|
||||||
text_end = s_end;
|
text_end = s_end;
|
||||||
}
|
}
|
||||||
|
if (s == text_end)
|
||||||
|
return;
|
||||||
|
|
||||||
// Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
|
// Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
|
||||||
const int vtx_count_max = (int)(text_end - s) * 4;
|
const int vtx_count_max = (int)(text_end - s) * 4;
|
||||||
@ -2733,7 +2845,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
|||||||
}
|
}
|
||||||
|
|
||||||
float char_width = 0.0f;
|
float char_width = 0.0f;
|
||||||
if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c))
|
if (const ImFontGlyph* glyph = FindGlyph((ImWchar)c))
|
||||||
{
|
{
|
||||||
char_width = glyph->AdvanceX * scale;
|
char_width = glyph->AdvanceX * scale;
|
||||||
|
|
||||||
@ -2818,6 +2930,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
|||||||
// - RenderMouseCursor()
|
// - RenderMouseCursor()
|
||||||
// - RenderArrowPointingAt()
|
// - RenderArrowPointingAt()
|
||||||
// - RenderRectFilledRangeH()
|
// - RenderRectFilledRangeH()
|
||||||
|
// - RenderPixelEllipsis()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor)
|
void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor)
|
||||||
@ -2926,6 +3039,16 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
|
|||||||
draw_list->PathFillConvex(col);
|
draw_list->PathFillConvex(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
|
||||||
|
// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
|
||||||
|
// the boldness or positioning of what the font uses...
|
||||||
|
void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col)
|
||||||
|
{
|
||||||
|
ImFont* font = draw_list->_Data->Font;
|
||||||
|
pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f);
|
||||||
|
for (int dot_n = 0; dot_n < count; dot_n++)
|
||||||
|
draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] Decompression code
|
// [SECTION] Decompression code
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// dear imgui, v1.65
|
// dear imgui, v1.67
|
||||||
// (internal structures/api)
|
// (internal structures/api)
|
||||||
|
|
||||||
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
|
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
|
||||||
@ -6,8 +6,27 @@
|
|||||||
// #define IMGUI_DEFINE_MATH_OPERATORS
|
// #define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
|
// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Index of this file:
|
||||||
|
// Header mess
|
||||||
|
// Forward declarations
|
||||||
|
// STB libraries includes
|
||||||
|
// Context pointer
|
||||||
|
// Generic helpers
|
||||||
|
// Misc data structures
|
||||||
|
// Main imgui context
|
||||||
|
// Tab bar, tab item
|
||||||
|
// Internal API
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Header mess
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef IMGUI_VERSION
|
#ifndef IMGUI_VERSION
|
||||||
#error Must include imgui.h before imgui_internal.h
|
#error Must include imgui.h before imgui_internal.h
|
||||||
#endif
|
#endif
|
||||||
@ -27,10 +46,14 @@
|
|||||||
#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
|
#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
|
||||||
#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
|
#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
|
||||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||||
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||||
|
#if __has_warning("-Wdouble-promotion")
|
||||||
|
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Forward Declarations
|
// Forward declarations
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct ImRect; // An axis-aligned rectangle (2 points)
|
struct ImRect; // An axis-aligned rectangle (2 points)
|
||||||
@ -49,6 +72,8 @@ struct ImGuiNextWindowData; // Storage for SetNexWindow** functions
|
|||||||
struct ImGuiPopupRef; // Storage for current popup stack
|
struct ImGuiPopupRef; // Storage for current popup stack
|
||||||
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
|
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
|
||||||
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
|
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
|
||||||
|
struct ImGuiTabBar; // Storage for a tab bar
|
||||||
|
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||||
struct ImGuiWindow; // Storage for one window
|
struct ImGuiWindow; // Storage for one window
|
||||||
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
|
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
|
||||||
struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session)
|
struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session)
|
||||||
@ -63,9 +88,10 @@ typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags:
|
|||||||
typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests
|
typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests
|
||||||
typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal
|
typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal
|
||||||
typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior()
|
typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior()
|
||||||
|
typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior()
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// STB libraries
|
// STB libraries includes
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ImGuiStb
|
namespace ImGuiStb
|
||||||
@ -81,7 +107,7 @@ namespace ImGuiStb
|
|||||||
} // namespace ImGuiStb
|
} // namespace ImGuiStb
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Context
|
// Context pointer
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef GImGui
|
#ifndef GImGui
|
||||||
@ -89,7 +115,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Helpers
|
// Generic helpers
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#define IM_PI 3.14159265358979323846f
|
#define IM_PI 3.14159265358979323846f
|
||||||
@ -98,6 +124,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
|
|||||||
#else
|
#else
|
||||||
#define IM_NEWLINE "\n"
|
#define IM_NEWLINE "\n"
|
||||||
#endif
|
#endif
|
||||||
|
#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
|
||||||
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
|
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
|
||||||
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
|
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
|
||||||
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
|
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
|
||||||
@ -139,8 +166,10 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2);
|
|||||||
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count);
|
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count);
|
||||||
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count);
|
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count);
|
||||||
IMGUI_API char* ImStrdup(const char* str);
|
IMGUI_API char* ImStrdup(const char* str);
|
||||||
|
IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str);
|
||||||
IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c);
|
IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c);
|
||||||
IMGUI_API int ImStrlenW(const ImWchar* str);
|
IMGUI_API int ImStrlenW(const ImWchar* str);
|
||||||
|
IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line
|
||||||
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
|
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
|
||||||
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
|
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
|
||||||
IMGUI_API void ImStrTrimBlanks(char* str);
|
IMGUI_API void ImStrTrimBlanks(char* str);
|
||||||
@ -211,11 +240,47 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a)
|
|||||||
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
|
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
|
||||||
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
||||||
|
|
||||||
|
// Helper: ImBoolVector. Store 1-bit per value.
|
||||||
|
// Note that Resize() currently clears the whole vector.
|
||||||
|
struct ImBoolVector
|
||||||
|
{
|
||||||
|
ImVector<int> Storage;
|
||||||
|
ImBoolVector() { }
|
||||||
|
void Resize(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||||
|
void Clear() { Storage.clear(); }
|
||||||
|
bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (Storage[off] & mask) != 0; }
|
||||||
|
void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,
|
||||||
|
// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.
|
||||||
|
typedef int ImPoolIdx;
|
||||||
|
template<typename T>
|
||||||
|
struct IMGUI_API ImPool
|
||||||
|
{
|
||||||
|
ImVector<T> Data; // Contiguous data
|
||||||
|
ImGuiStorage Map; // ID->Index
|
||||||
|
ImPoolIdx FreeIdx; // Next free idx to use
|
||||||
|
|
||||||
|
ImPool() { FreeIdx = 0; }
|
||||||
|
~ImPool() { Clear(); }
|
||||||
|
T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; }
|
||||||
|
T* GetByIndex(ImPoolIdx n) { return &Data[n]; }
|
||||||
|
ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); }
|
||||||
|
T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); }
|
||||||
|
void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; }
|
||||||
|
T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; }
|
||||||
|
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
|
||||||
|
void Remove(ImGuiID key, ImPoolIdx idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
|
||||||
|
void Reserve(int capacity) { Data.reserve(capacity); Map.Data.reserve(capacity); }
|
||||||
|
int GetSize() const { return Data.Size; }
|
||||||
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Types
|
// Misc data structures
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches)
|
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
|
||||||
struct ImVec1
|
struct ImVec1
|
||||||
{
|
{
|
||||||
float x;
|
float x;
|
||||||
@ -248,6 +313,12 @@ enum ImGuiSliderFlags_
|
|||||||
ImGuiSliderFlags_Vertical = 1 << 0
|
ImGuiSliderFlags_Vertical = 1 << 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ImGuiDragFlags_
|
||||||
|
{
|
||||||
|
ImGuiDragFlags_None = 0,
|
||||||
|
ImGuiDragFlags_Vertical = 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
enum ImGuiColumnsFlags_
|
enum ImGuiColumnsFlags_
|
||||||
{
|
{
|
||||||
// Default: 0
|
// Default: 0
|
||||||
@ -282,15 +353,25 @@ enum ImGuiItemStatusFlags_
|
|||||||
ImGuiItemStatusFlags_HoveredRect = 1 << 0,
|
ImGuiItemStatusFlags_HoveredRect = 1 << 0,
|
||||||
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
|
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
|
||||||
ImGuiItemStatusFlags_Edited = 1 << 2 // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
|
ImGuiItemStatusFlags_Edited = 1 << 2 // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||||
|
, // [imgui-test only]
|
||||||
|
ImGuiItemStatusFlags_Openable = 1 << 10, //
|
||||||
|
ImGuiItemStatusFlags_Opened = 1 << 11, //
|
||||||
|
ImGuiItemStatusFlags_Checkable = 1 << 12, //
|
||||||
|
ImGuiItemStatusFlags_Checked = 1 << 13 //
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: this is in development, not exposed/functional as a generic feature yet.
|
// FIXME: this is in development, not exposed/functional as a generic feature yet.
|
||||||
|
// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2
|
||||||
enum ImGuiLayoutType_
|
enum ImGuiLayoutType_
|
||||||
{
|
{
|
||||||
ImGuiLayoutType_Vertical,
|
ImGuiLayoutType_Horizontal = 0,
|
||||||
ImGuiLayoutType_Horizontal
|
ImGuiLayoutType_Vertical = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// X/Y enums are fixed to 0/1 so they may be used to index ImVec2
|
||||||
enum ImGuiAxis
|
enum ImGuiAxis
|
||||||
{
|
{
|
||||||
ImGuiAxis_None = -1,
|
ImGuiAxis_None = -1,
|
||||||
@ -360,6 +441,13 @@ enum ImGuiNavForward
|
|||||||
ImGuiNavForward_ForwardActive
|
ImGuiNavForward_ForwardActive
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ImGuiNavLayer
|
||||||
|
{
|
||||||
|
ImGuiNavLayer_Main = 0, // Main scrolling layer
|
||||||
|
ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu)
|
||||||
|
ImGuiNavLayer_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
enum ImGuiPopupPositionPolicy
|
enum ImGuiPopupPositionPolicy
|
||||||
{
|
{
|
||||||
ImGuiPopupPositionPolicy_Default,
|
ImGuiPopupPositionPolicy_Default,
|
||||||
@ -632,11 +720,21 @@ struct ImGuiNextWindowData
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ImGuiTabBarSortItem
|
||||||
|
{
|
||||||
|
int Index;
|
||||||
|
float Width;
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
// Main imgui context
|
// Main imgui context
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct ImGuiContext
|
struct ImGuiContext
|
||||||
{
|
{
|
||||||
bool Initialized;
|
bool Initialized;
|
||||||
bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()/Render()
|
bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()
|
||||||
|
bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame()
|
||||||
bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
|
bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
|
||||||
ImGuiIO IO;
|
ImGuiIO IO;
|
||||||
ImGuiStyle Style;
|
ImGuiStyle Style;
|
||||||
@ -649,7 +747,8 @@ struct ImGuiContext
|
|||||||
int FrameCount;
|
int FrameCount;
|
||||||
int FrameCountEnded;
|
int FrameCountEnded;
|
||||||
int FrameCountRendered;
|
int FrameCountRendered;
|
||||||
ImVector<ImGuiWindow*> Windows;
|
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
|
||||||
|
ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front
|
||||||
ImVector<ImGuiWindow*> WindowsSortBuffer;
|
ImVector<ImGuiWindow*> WindowsSortBuffer;
|
||||||
ImVector<ImGuiWindow*> CurrentWindowStack;
|
ImVector<ImGuiWindow*> CurrentWindowStack;
|
||||||
ImGuiStorage WindowsById;
|
ImGuiStorage WindowsById;
|
||||||
@ -660,7 +759,8 @@ struct ImGuiContext
|
|||||||
ImGuiID HoveredId; // Hovered widget
|
ImGuiID HoveredId; // Hovered widget
|
||||||
bool HoveredIdAllowOverlap;
|
bool HoveredIdAllowOverlap;
|
||||||
ImGuiID HoveredIdPreviousFrame;
|
ImGuiID HoveredIdPreviousFrame;
|
||||||
float HoveredIdTimer;
|
float HoveredIdTimer; // Measure contiguous hovering time
|
||||||
|
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
|
||||||
ImGuiID ActiveId; // Active widget
|
ImGuiID ActiveId; // Active widget
|
||||||
ImGuiID ActiveIdPreviousFrame;
|
ImGuiID ActiveIdPreviousFrame;
|
||||||
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
|
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
|
||||||
@ -677,12 +777,13 @@ struct ImGuiContext
|
|||||||
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
|
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
|
||||||
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
|
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
|
||||||
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
|
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
|
||||||
|
ImVec2 LastValidMousePos;
|
||||||
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
|
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
|
||||||
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
|
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
|
||||||
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
|
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
|
||||||
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
|
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
|
||||||
ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent)
|
ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent)
|
||||||
ImVector<ImGuiPopupRef> CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame)
|
ImVector<ImGuiPopupRef> BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
|
||||||
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
|
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
|
||||||
bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
|
bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
|
||||||
ImGuiCond NextTreeNodeOpenCond;
|
ImGuiCond NextTreeNodeOpenCond;
|
||||||
@ -697,7 +798,7 @@ struct ImGuiContext
|
|||||||
ImGuiID NavJustTabbedId; // Just tabbed to this id.
|
ImGuiID NavJustTabbedId; // Just tabbed to this id.
|
||||||
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest)
|
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest)
|
||||||
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame
|
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame
|
||||||
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode?
|
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard.
|
||||||
ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring.
|
ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring.
|
||||||
int NavScoringCount; // Metrics for debugging
|
int NavScoringCount; // Metrics for debugging
|
||||||
ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most.
|
ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most.
|
||||||
@ -706,7 +807,7 @@ struct ImGuiContext
|
|||||||
float NavWindowingTimer;
|
float NavWindowingTimer;
|
||||||
float NavWindowingHighlightAlpha;
|
float NavWindowingHighlightAlpha;
|
||||||
bool NavWindowingToggleLayer;
|
bool NavWindowingToggleLayer;
|
||||||
int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
|
ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
|
||||||
int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
|
int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
|
||||||
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid
|
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid
|
||||||
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
|
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
|
||||||
@ -751,6 +852,11 @@ struct ImGuiContext
|
|||||||
ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly
|
ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly
|
||||||
unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads
|
unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads
|
||||||
|
|
||||||
|
// Tab bars
|
||||||
|
ImPool<ImGuiTabBar> TabBars;
|
||||||
|
ImVector<ImGuiTabBar*> CurrentTabBar;
|
||||||
|
ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer;
|
||||||
|
|
||||||
// Widget state
|
// Widget state
|
||||||
ImGuiInputTextState InputTextState;
|
ImGuiInputTextState InputTextState;
|
||||||
ImFont InputTextPasswordFont;
|
ImFont InputTextPasswordFont;
|
||||||
@ -763,6 +869,8 @@ struct ImGuiContext
|
|||||||
ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
|
ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
|
||||||
int TooltipOverrideCount;
|
int TooltipOverrideCount;
|
||||||
ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined
|
ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined
|
||||||
|
|
||||||
|
// Platform support
|
||||||
ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor
|
ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
@ -791,7 +899,7 @@ struct ImGuiContext
|
|||||||
ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL)
|
ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL)
|
||||||
{
|
{
|
||||||
Initialized = false;
|
Initialized = false;
|
||||||
FrameScopeActive = false;
|
FrameScopeActive = FrameScopePushedImplicitWindow = false;
|
||||||
Font = NULL;
|
Font = NULL;
|
||||||
FontSize = FontBaseSize = 0.0f;
|
FontSize = FontBaseSize = 0.0f;
|
||||||
FontAtlasOwnedByContext = shared_font_atlas ? false : true;
|
FontAtlasOwnedByContext = shared_font_atlas ? false : true;
|
||||||
@ -807,7 +915,7 @@ struct ImGuiContext
|
|||||||
HoveredId = 0;
|
HoveredId = 0;
|
||||||
HoveredIdAllowOverlap = false;
|
HoveredIdAllowOverlap = false;
|
||||||
HoveredIdPreviousFrame = 0;
|
HoveredIdPreviousFrame = 0;
|
||||||
HoveredIdTimer = 0.0f;
|
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
|
||||||
ActiveId = 0;
|
ActiveId = 0;
|
||||||
ActiveIdPreviousFrame = 0;
|
ActiveIdPreviousFrame = 0;
|
||||||
ActiveIdIsAlive = 0;
|
ActiveIdIsAlive = 0;
|
||||||
@ -823,6 +931,7 @@ struct ImGuiContext
|
|||||||
ActiveIdSource = ImGuiInputSource_None;
|
ActiveIdSource = ImGuiInputSource_None;
|
||||||
LastActiveId = 0;
|
LastActiveId = 0;
|
||||||
LastActiveIdTimer = 0.0f;
|
LastActiveIdTimer = 0.0f;
|
||||||
|
LastValidMousePos = ImVec2(0.0f, 0.0f);
|
||||||
MovingWindow = NULL;
|
MovingWindow = NULL;
|
||||||
NextTreeNodeOpenVal = false;
|
NextTreeNodeOpenVal = false;
|
||||||
NextTreeNodeOpenCond = 0;
|
NextTreeNodeOpenCond = 0;
|
||||||
@ -836,7 +945,7 @@ struct ImGuiContext
|
|||||||
NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL;
|
NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL;
|
||||||
NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
|
NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
|
||||||
NavWindowingToggleLayer = false;
|
NavWindowingToggleLayer = false;
|
||||||
NavLayer = 0;
|
NavLayer = ImGuiNavLayer_Main;
|
||||||
NavIdTabCounter = INT_MAX;
|
NavIdTabCounter = INT_MAX;
|
||||||
NavIdIsAlive = false;
|
NavIdIsAlive = false;
|
||||||
NavMousePosDirty = false;
|
NavMousePosDirty = false;
|
||||||
@ -897,13 +1006,13 @@ struct ImGuiContext
|
|||||||
// This is going to be exposed in imgui.h when stabilized enough.
|
// This is going to be exposed in imgui.h when stabilized enough.
|
||||||
enum ImGuiItemFlags_
|
enum ImGuiItemFlags_
|
||||||
{
|
{
|
||||||
ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // true
|
ImGuiItemFlags_NoTabStop = 1 << 0, // false
|
||||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||||
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
|
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
|
||||||
ImGuiItemFlags_NoNav = 1 << 3, // false
|
ImGuiItemFlags_NoNav = 1 << 3, // false
|
||||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
|
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
|
||||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
|
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
|
||||||
ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus
|
ImGuiItemFlags_Default_ = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
|
// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
|
||||||
@ -925,12 +1034,12 @@ struct IMGUI_API ImGuiWindowTempData
|
|||||||
ImGuiItemStatusFlags LastItemStatusFlags;
|
ImGuiItemStatusFlags LastItemStatusFlags;
|
||||||
ImRect LastItemRect; // Interaction rect
|
ImRect LastItemRect; // Interaction rect
|
||||||
ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
|
ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
|
||||||
bool NavHideHighlightOneFrame;
|
ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
|
||||||
bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
|
|
||||||
int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
|
|
||||||
int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping.
|
int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping.
|
||||||
int NavLayerActiveMask; // Which layer have been written to (result from previous frame)
|
int NavLayerActiveMask; // Which layer have been written to (result from previous frame)
|
||||||
int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame)
|
int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame)
|
||||||
|
bool NavHideHighlightOneFrame;
|
||||||
|
bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
|
||||||
bool MenuBarAppending; // FIXME: Remove this
|
bool MenuBarAppending; // FIXME: Remove this
|
||||||
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
|
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
|
||||||
ImVector<ImGuiWindow*> ChildWindows;
|
ImVector<ImGuiWindow*> ChildWindows;
|
||||||
@ -946,7 +1055,7 @@ struct IMGUI_API ImGuiWindowTempData
|
|||||||
ImVector<float> ItemWidthStack;
|
ImVector<float> ItemWidthStack;
|
||||||
ImVector<float> TextWrapPosStack;
|
ImVector<float> TextWrapPosStack;
|
||||||
ImVector<ImGuiGroupData>GroupStack;
|
ImVector<ImGuiGroupData>GroupStack;
|
||||||
int StackSizesBackup[6]; // Store size of various stacks for asserting
|
short StackSizesBackup[6]; // Store size of various stacks for asserting
|
||||||
|
|
||||||
ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
|
ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
|
||||||
ImVec1 GroupOffset;
|
ImVec1 GroupOffset;
|
||||||
@ -964,11 +1073,11 @@ struct IMGUI_API ImGuiWindowTempData
|
|||||||
LastItemId = 0;
|
LastItemId = 0;
|
||||||
LastItemStatusFlags = 0;
|
LastItemStatusFlags = 0;
|
||||||
LastItemRect = LastItemDisplayRect = ImRect();
|
LastItemRect = LastItemDisplayRect = ImRect();
|
||||||
|
NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
|
||||||
|
NavLayerCurrent = ImGuiNavLayer_Main;
|
||||||
|
NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
|
||||||
NavHideHighlightOneFrame = false;
|
NavHideHighlightOneFrame = false;
|
||||||
NavHasScroll = false;
|
NavHasScroll = false;
|
||||||
NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
|
|
||||||
NavLayerCurrent = 0;
|
|
||||||
NavLayerCurrentMask = 1 << 0;
|
|
||||||
MenuBarAppending = false;
|
MenuBarAppending = false;
|
||||||
MenuBarOffset = ImVec2(0.0f, 0.0f);
|
MenuBarOffset = ImVec2(0.0f, 0.0f);
|
||||||
StateStorage = NULL;
|
StateStorage = NULL;
|
||||||
@ -1000,6 +1109,7 @@ struct IMGUI_API ImGuiWindow
|
|||||||
ImVec2 WindowPadding; // Window padding at the time of begin.
|
ImVec2 WindowPadding; // Window padding at the time of begin.
|
||||||
float WindowRounding; // Window rounding at the time of begin.
|
float WindowRounding; // Window rounding at the time of begin.
|
||||||
float WindowBorderSize; // Window border size at the time of begin.
|
float WindowBorderSize; // Window border size at the time of begin.
|
||||||
|
int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)!
|
||||||
ImGuiID MoveId; // == window->GetID("#MOVE")
|
ImGuiID MoveId; // == window->GetID("#MOVE")
|
||||||
ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
|
ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
|
||||||
ImVec2 Scroll;
|
ImVec2 Scroll;
|
||||||
@ -1016,9 +1126,9 @@ struct IMGUI_API ImGuiWindow
|
|||||||
bool Appearing; // Set during the frame where the window is appearing (or re-appearing)
|
bool Appearing; // Set during the frame where the window is appearing (or re-appearing)
|
||||||
bool Hidden; // Do not display (== (HiddenFramesForResize > 0) ||
|
bool Hidden; // Do not display (== (HiddenFramesForResize > 0) ||
|
||||||
bool HasCloseButton; // Set when the window has a close button (p_open != NULL)
|
bool HasCloseButton; // Set when the window has a close button (p_open != NULL)
|
||||||
int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
|
short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
|
||||||
int BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
|
short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
|
||||||
int BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
|
short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
|
||||||
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
|
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
|
||||||
int AutoFitFramesX, AutoFitFramesY;
|
int AutoFitFramesX, AutoFitFramesY;
|
||||||
bool AutoFitOnlyGrows;
|
bool AutoFitOnlyGrows;
|
||||||
@ -1054,8 +1164,8 @@ struct IMGUI_API ImGuiWindow
|
|||||||
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
|
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
|
||||||
|
|
||||||
ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
|
ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
|
||||||
ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1)
|
ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1)
|
||||||
ImRect NavRectRel[2]; // Reference rectangle, in window relative space
|
ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space
|
||||||
|
|
||||||
// Navigation / Focus
|
// Navigation / Focus
|
||||||
// FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext
|
// FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext
|
||||||
@ -1098,6 +1208,59 @@ struct ImGuiItemHoveredDataBackup
|
|||||||
void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
|
void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Tab bar, tab item
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum ImGuiTabBarFlagsPrivate_
|
||||||
|
{
|
||||||
|
ImGuiTabBarFlags_DockNode = 1 << 20, // [Docking: Unused in Master Branch] Part of a dock node
|
||||||
|
ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // [Docking: Unused in Master Branch] Part of an explicit dockspace node node
|
||||||
|
ImGuiTabBarFlags_IsFocused = 1 << 22,
|
||||||
|
ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage for one active tab item (sizeof() 26~32 bytes)
|
||||||
|
struct ImGuiTabItem
|
||||||
|
{
|
||||||
|
ImGuiID ID;
|
||||||
|
ImGuiTabItemFlags Flags;
|
||||||
|
int LastFrameVisible;
|
||||||
|
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
|
||||||
|
float Offset; // Position relative to beginning of tab
|
||||||
|
float Width; // Width currently displayed
|
||||||
|
float WidthContents; // Width of actual contents, stored during BeginTabItem() call
|
||||||
|
|
||||||
|
ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage for a tab bar (sizeof() 92~96 bytes)
|
||||||
|
struct ImGuiTabBar
|
||||||
|
{
|
||||||
|
ImVector<ImGuiTabItem> Tabs;
|
||||||
|
ImGuiID ID; // Zero for tab-bars used by docking
|
||||||
|
ImGuiID SelectedTabId; // Selected tab
|
||||||
|
ImGuiID NextSelectedTabId;
|
||||||
|
ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview)
|
||||||
|
int CurrFrameVisible;
|
||||||
|
int PrevFrameVisible;
|
||||||
|
ImRect BarRect;
|
||||||
|
float ContentsHeight;
|
||||||
|
float OffsetMax; // Distance from BarRect.Min.x, locked during layout
|
||||||
|
float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set.
|
||||||
|
float ScrollingAnim;
|
||||||
|
float ScrollingTarget;
|
||||||
|
ImGuiTabBarFlags Flags;
|
||||||
|
ImGuiID ReorderRequestTabId;
|
||||||
|
int ReorderRequestDir;
|
||||||
|
bool WantLayout;
|
||||||
|
bool VisibleTabWasSubmitted;
|
||||||
|
short LastTabItemIdx; // For BeginTabItem()/EndTabItem()
|
||||||
|
|
||||||
|
ImGuiTabBar();
|
||||||
|
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
|
||||||
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Internal API
|
// Internal API
|
||||||
// No guarantee of forward compatibility here.
|
// No guarantee of forward compatibility here.
|
||||||
@ -1111,18 +1274,23 @@ namespace ImGui
|
|||||||
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
||||||
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
||||||
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
|
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
|
||||||
|
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
|
||||||
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
|
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
|
||||||
IMGUI_API void FocusWindow(ImGuiWindow* window);
|
IMGUI_API void FocusWindow(ImGuiWindow* window);
|
||||||
IMGUI_API void FocusFrontMostActiveWindowIgnoringOne(ImGuiWindow* ignore_window);
|
IMGUI_API void FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window);
|
||||||
IMGUI_API void BringWindowToFront(ImGuiWindow* window);
|
IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window);
|
||||||
IMGUI_API void BringWindowToBack(ImGuiWindow* window);
|
IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window);
|
||||||
|
IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window);
|
||||||
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
|
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
|
||||||
IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window);
|
IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window);
|
||||||
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
|
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
|
||||||
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
|
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
|
||||||
IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
|
IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
|
||||||
IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
|
IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
|
||||||
|
IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window);
|
||||||
|
IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window);
|
||||||
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
|
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
|
||||||
|
|
||||||
IMGUI_API void SetCurrentFont(ImFont* font);
|
IMGUI_API void SetCurrentFont(ImFont* font);
|
||||||
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
|
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
|
||||||
|
|
||||||
@ -1133,7 +1301,8 @@ namespace ImGui
|
|||||||
// NewFrame
|
// NewFrame
|
||||||
IMGUI_API void UpdateHoveredWindowAndCaptureFlags();
|
IMGUI_API void UpdateHoveredWindowAndCaptureFlags();
|
||||||
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
|
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
|
||||||
IMGUI_API void UpdateMouseMovingWindow();
|
IMGUI_API void UpdateMouseMovingWindowNewFrame();
|
||||||
|
IMGUI_API void UpdateMouseMovingWindowEndFrame();
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
IMGUI_API void MarkIniSettingsDirty();
|
IMGUI_API void MarkIniSettingsDirty();
|
||||||
@ -1170,10 +1339,9 @@ namespace ImGui
|
|||||||
|
|
||||||
// Popups, Modals, Tooltips
|
// Popups, Modals, Tooltips
|
||||||
IMGUI_API void OpenPopupEx(ImGuiID id);
|
IMGUI_API void OpenPopupEx(ImGuiID id);
|
||||||
IMGUI_API void ClosePopup(ImGuiID id);
|
IMGUI_API void ClosePopupToLevel(int remaining, bool apply_focus_to_window_under);
|
||||||
IMGUI_API void ClosePopupToLevel(int remaining);
|
|
||||||
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window);
|
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window);
|
||||||
IMGUI_API bool IsPopupOpen(ImGuiID id);
|
IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack!
|
||||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
|
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
|
||||||
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
|
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
|
||||||
IMGUI_API ImGuiWindow* GetFrontMostPopupModal();
|
IMGUI_API ImGuiWindow* GetFrontMostPopupModal();
|
||||||
@ -1209,12 +1377,24 @@ namespace ImGui
|
|||||||
IMGUI_API void EndColumns(); // close columns
|
IMGUI_API void EndColumns(); // close columns
|
||||||
IMGUI_API void PushColumnClipRect(int column_index = -1);
|
IMGUI_API void PushColumnClipRect(int column_index = -1);
|
||||||
|
|
||||||
|
// Tab Bars
|
||||||
|
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
|
||||||
|
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||||
|
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||||
|
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||||
|
IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
|
||||||
|
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags);
|
||||||
|
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button);
|
||||||
|
IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);
|
||||||
|
IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id);
|
||||||
|
|
||||||
// Render helpers
|
// Render helpers
|
||||||
// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
|
// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
|
||||||
// NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)
|
// NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)
|
||||||
IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
|
IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
|
||||||
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
|
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
|
||||||
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL);
|
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL);
|
||||||
|
IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
|
||||||
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
|
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
|
||||||
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
|
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
|
||||||
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
|
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
|
||||||
@ -1229,6 +1409,7 @@ namespace ImGui
|
|||||||
IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow);
|
IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow);
|
||||||
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
|
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
|
||||||
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
|
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
|
||||||
|
IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col);
|
||||||
|
|
||||||
// Widgets
|
// Widgets
|
||||||
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
|
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
|
||||||
@ -1240,7 +1421,7 @@ namespace ImGui
|
|||||||
|
|
||||||
// Widgets low-level behaviors
|
// Widgets low-level behaviors
|
||||||
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
|
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
|
||||||
IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power);
|
IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags);
|
||||||
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
|
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
|
||||||
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
|
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
|
||||||
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
|
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
|
||||||
@ -1250,7 +1431,7 @@ namespace ImGui
|
|||||||
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
|
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
|
||||||
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
|
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
|
||||||
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); "
|
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); "
|
||||||
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power);
|
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power, ImGuiDragFlags flags);
|
||||||
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, const T v_min, const T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
|
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, const T v_min, const T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
|
||||||
template<typename T, typename FLOAT_T> IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos);
|
template<typename T, typename FLOAT_T> IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos);
|
||||||
template<typename T, typename SIGNED_T> IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);
|
template<typename T, typename SIGNED_T> IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);
|
||||||
@ -1277,11 +1458,23 @@ namespace ImGui
|
|||||||
IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
|
IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
|
||||||
IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
|
IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
|
||||||
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
|
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
|
||||||
IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc);
|
IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
|
||||||
IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
|
IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
|
||||||
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
|
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
|
||||||
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
|
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
|
||||||
|
|
||||||
|
// Test engine hooks (imgui-test)
|
||||||
|
//#define IMGUI_ENABLE_TEST_ENGINE
|
||||||
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||||
|
extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
|
||||||
|
extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx);
|
||||||
|
extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
|
||||||
|
extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, int flags);
|
||||||
|
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags
|
||||||
|
#else
|
||||||
|
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "TextEditor.h"
|
#include "TextEditor.h"
|
||||||
|
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#include "../imgui/imgui.h" // for imGui::GetCurrentWindow()
|
||||||
|
|
||||||
namespace tracy
|
namespace tracy
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -34,20 +37,21 @@ TextEditor::TextEditor()
|
|||||||
, mReadOnly(false)
|
, mReadOnly(false)
|
||||||
, mWithinRender(false)
|
, mWithinRender(false)
|
||||||
, mScrollToCursor(false)
|
, mScrollToCursor(false)
|
||||||
|
, mScrollToTop(false)
|
||||||
, mTextChanged(false)
|
, mTextChanged(false)
|
||||||
, mTextStart(20.0f)
|
, mTextStart(20.0f)
|
||||||
, mLeftMargin(10)
|
, mLeftMargin(10)
|
||||||
, mColorRangeMin(0)
|
, mColorRangeMin(0)
|
||||||
, mColorRangeMax(0)
|
, mColorRangeMax(0)
|
||||||
, mSelectionMode(SelectionMode::Normal)
|
, mSelectionMode(SelectionMode::Normal)
|
||||||
, mCheckMultilineComments(true)
|
, mCheckComments(true)
|
||||||
|
, mLastClick(-1.0f)
|
||||||
{
|
{
|
||||||
SetPalette(GetDarkPalette());
|
SetPalette(GetDarkPalette());
|
||||||
SetLanguageDefinition(LanguageDefinition::HLSL());
|
SetLanguageDefinition(LanguageDefinition::HLSL());
|
||||||
mLines.push_back(Line());
|
mLines.push_back(Line());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextEditor::~TextEditor()
|
TextEditor::~TextEditor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -63,7 +67,7 @@ void TextEditor::SetLanguageDefinition(const LanguageDefinition & aLanguageDef)
|
|||||||
|
|
||||||
void TextEditor::SetPalette(const Palette & aValue)
|
void TextEditor::SetPalette(const Palette & aValue)
|
||||||
{
|
{
|
||||||
mPalette = aValue;
|
mPaletteBase = aValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextEditor::AppendBuffer(std::string& aBuffer, char chr, int aIndex)
|
int TextEditor::AppendBuffer(std::string& aBuffer, char chr, int aIndex)
|
||||||
@ -250,7 +254,6 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2& aPositi
|
|||||||
/*
|
/*
|
||||||
Compute columnCoord according to text size
|
Compute columnCoord according to text size
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int columnCoord = 0;
|
int columnCoord = 0;
|
||||||
float columnWidth = 0.0f;
|
float columnWidth = 0.0f;
|
||||||
std::string cumulatedString = "";
|
std::string cumulatedString = "";
|
||||||
@ -262,7 +265,7 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2& aPositi
|
|||||||
|
|
||||||
// First we find the hovered column coord.
|
// First we find the hovered column coord.
|
||||||
while (mTextStart + cumulatedStringWidth[0] < local.x &&
|
while (mTextStart + cumulatedStringWidth[0] < local.x &&
|
||||||
columnCoord < line.size())
|
(size_t)columnCoord < line.size())
|
||||||
{
|
{
|
||||||
cumulatedStringWidth[1] = cumulatedStringWidth[0];
|
cumulatedStringWidth[1] = cumulatedStringWidth[0];
|
||||||
cumulatedString += line[columnCoord].mChar;
|
cumulatedString += line[columnCoord].mChar;
|
||||||
@ -273,7 +276,7 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2& aPositi
|
|||||||
|
|
||||||
// Then we reduce by 1 column coord if cursor is on the left side of the hovered column.
|
// Then we reduce by 1 column coord if cursor is on the left side of the hovered column.
|
||||||
if (mTextStart + cumulatedStringWidth[0] - columnWidth / 2.0f > local.x)
|
if (mTextStart + cumulatedStringWidth[0] - columnWidth / 2.0f > local.x)
|
||||||
columnCoord = std::max(0, --columnCoord);
|
columnCoord = std::max(0, columnCoord - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SanitizeCoordinates(Coordinates(lineNo, columnCoord));
|
return SanitizeCoordinates(Coordinates(lineNo, columnCoord));
|
||||||
@ -337,7 +340,7 @@ void TextEditor::RemoveLine(int aStart, int aEnd)
|
|||||||
{
|
{
|
||||||
assert(!mReadOnly);
|
assert(!mReadOnly);
|
||||||
assert(aEnd >= aStart);
|
assert(aEnd >= aStart);
|
||||||
assert(mLines.size() > aEnd - aStart);
|
assert(mLines.size() > (size_t)(aEnd - aStart));
|
||||||
|
|
||||||
ErrorMarkers etmp;
|
ErrorMarkers etmp;
|
||||||
for (auto& i : mErrorMarkers)
|
for (auto& i : mErrorMarkers)
|
||||||
@ -432,25 +435,28 @@ std::string TextEditor::GetWordAt(const Coordinates & aCoords) const
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
ImU32 TextEditor::GetGlyphColor(const Glyph & aGlyph) const
|
||||||
{
|
{
|
||||||
mWithinRender = true;
|
if (aGlyph.mComment)
|
||||||
mTextChanged = false;
|
return mPalette[(int)PaletteIndex::Comment];
|
||||||
mCursorPositionChanged = false;
|
if (aGlyph.mMultiLineComment)
|
||||||
|
return mPalette[(int)PaletteIndex::MultiLineComment];
|
||||||
|
auto const color = mPalette[(int)aGlyph.mColorIndex];
|
||||||
|
if (aGlyph.mPreprocessor)
|
||||||
|
{
|
||||||
|
const auto ppcolor = mPalette[(int)PaletteIndex::Preprocessor];
|
||||||
|
const int c0 = ((ppcolor & 0xff) + (color & 0xff)) / 2;
|
||||||
|
const int c1 = (((ppcolor >> 8) & 0xff) + ((color >> 8) & 0xff)) / 2;
|
||||||
|
const int c2 = (((ppcolor >> 16) & 0xff) + ((color >> 16) & 0xff)) / 2;
|
||||||
|
const int c3 = (((ppcolor >> 24) & 0xff) + ((color >> 24) & 0xff)) / 2;
|
||||||
|
return ImU32(c0 | (c1 << 8) | (c2 << 16) | (c3 << 24));
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, ImGui::ColorConvertU32ToFloat4(mPalette[(int)PaletteIndex::Background]));
|
return color;
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
}
|
||||||
ImGui::BeginChild(aTitle, aSize, aBorder, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NoMove);
|
|
||||||
|
|
||||||
/* Compute mCharAdvance regarding to scaled font size (Ctrl + mouse wheel)*/
|
void TextEditor::HandleKeyboardInputs()
|
||||||
const float fontSize = ImGui::CalcTextSize("#").x;
|
{
|
||||||
mCharAdvance = ImVec2(fontSize , ImGui::GetTextLineHeightWithSpacing() * mLineSpacing);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Keyboard inputs
|
|
||||||
*/
|
|
||||||
|
|
||||||
ImGui::PushAllowKeyboardFocus(true);
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
auto shift = io.KeyShift;
|
auto shift = io.KeyShift;
|
||||||
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
|
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
|
||||||
@ -465,11 +471,11 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
io.WantCaptureKeyboard = true;
|
io.WantCaptureKeyboard = true;
|
||||||
io.WantTextInput = true;
|
io.WantTextInput = true;
|
||||||
|
|
||||||
if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed('Z'))
|
if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
|
||||||
Undo();
|
Undo();
|
||||||
else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||||
Undo();
|
Undo();
|
||||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed('Y'))
|
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
|
||||||
Redo();
|
Redo();
|
||||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
|
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
|
||||||
MoveUp(1, shift);
|
MoveUp(1, shift);
|
||||||
@ -495,17 +501,17 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
Delete();
|
Delete();
|
||||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||||
BackSpace();
|
BackSpace();
|
||||||
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(45))
|
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||||
mOverwrite ^= true;
|
mOverwrite ^= true;
|
||||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(45))
|
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||||
Copy();
|
Copy();
|
||||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed('C'))
|
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||||
Copy();
|
Copy();
|
||||||
else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(45))
|
else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||||
Paste();
|
Paste();
|
||||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed('V'))
|
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
|
||||||
Paste();
|
Paste();
|
||||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed('X'))
|
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
|
||||||
Cut();
|
Cut();
|
||||||
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||||
Cut();
|
Cut();
|
||||||
@ -513,11 +519,13 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
SelectAll();
|
SelectAll();
|
||||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
|
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
|
||||||
EnterCharacter('\n', false);
|
EnterCharacter('\n', false);
|
||||||
|
else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
|
||||||
|
EnterCharacter('\t', shift);
|
||||||
else if (!IsReadOnly() && !ctrl && !alt)
|
else if (!IsReadOnly() && !ctrl && !alt)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < sizeof(io.InputCharacters) / sizeof(io.InputCharacters[0]); i++)
|
for (int i = 0; i < io.InputQueueCharacters.Size; i++)
|
||||||
{
|
{
|
||||||
auto c = (unsigned char)io.InputCharacters[i];
|
auto c = (unsigned char)io.InputQueueCharacters[i];
|
||||||
if (c != 0)
|
if (c != 0)
|
||||||
{
|
{
|
||||||
if (isprint(c) || isspace(c))
|
if (isprint(c) || isspace(c))
|
||||||
@ -526,22 +534,26 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
io.InputQueueCharacters.resize(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void TextEditor::HandleMouseInputs()
|
||||||
Mouse inputs
|
{
|
||||||
*/
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
auto shift = io.KeyShift;
|
||||||
|
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
|
||||||
|
auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
|
||||||
|
|
||||||
if (ImGui::IsWindowHovered())
|
if (ImGui::IsWindowHovered())
|
||||||
{
|
{
|
||||||
static float lastClick = -1.0f;
|
|
||||||
if (!shift && !alt)
|
if (!shift && !alt)
|
||||||
{
|
{
|
||||||
auto click = ImGui::IsMouseClicked(0);
|
auto click = ImGui::IsMouseClicked(0);
|
||||||
auto doubleClick = ImGui::IsMouseDoubleClicked(0);
|
auto doubleClick = ImGui::IsMouseDoubleClicked(0);
|
||||||
auto t = ImGui::GetTime();
|
auto t = ImGui::GetTime();
|
||||||
auto tripleClick = click && !doubleClick && t - lastClick < io.MouseDoubleClickTime;
|
auto tripleClick = click && !doubleClick && (mLastClick != -1.0f && (t - mLastClick) < io.MouseDoubleClickTime);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Left mouse button triple click
|
Left mouse button triple click
|
||||||
@ -556,7 +568,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastClick = -1.0f;
|
mLastClick = -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -575,13 +587,12 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastClick = (float)ImGui::GetTime();
|
mLastClick = (float)ImGui::GetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Left mouse button click
|
Left mouse button click
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if (click)
|
else if (click)
|
||||||
{
|
{
|
||||||
mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = SanitizeCoordinates(ScreenPosToCoordinates(ImGui::GetMousePos()));
|
mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = SanitizeCoordinates(ScreenPosToCoordinates(ImGui::GetMousePos()));
|
||||||
@ -591,7 +602,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
mSelectionMode = SelectionMode::Normal;
|
mSelectionMode = SelectionMode::Normal;
|
||||||
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
|
||||||
|
|
||||||
lastClick = (float)ImGui::GetTime();
|
mLastClick = (float)ImGui::GetTime();
|
||||||
}
|
}
|
||||||
// Mouse left button dragging (=> update selection)
|
// Mouse left button dragging (=> update selection)
|
||||||
else if (ImGui::IsMouseDragging(0) && ImGui::IsMouseDown(0))
|
else if (ImGui::IsMouseDragging(0) && ImGui::IsMouseDown(0))
|
||||||
@ -602,14 +613,35 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColorizeInternal();
|
void TextEditor::Render()
|
||||||
|
{
|
||||||
|
/* Compute mCharAdvance regarding to scaled font size (Ctrl + mouse wheel)*/
|
||||||
|
const float fontSize = ImGui::CalcTextSize("#").x;
|
||||||
|
mCharAdvance = ImVec2(fontSize, ImGui::GetTextLineHeightWithSpacing() * mLineSpacing);
|
||||||
|
|
||||||
|
/* Update palette with the current alpha from style */
|
||||||
|
for (int i = 0; i < (int)PaletteIndex::Max; ++i)
|
||||||
|
{
|
||||||
|
auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]);
|
||||||
|
color.w *= ImGui::GetStyle().Alpha;
|
||||||
|
mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
|
||||||
|
}
|
||||||
|
|
||||||
static std::string buffer;
|
static std::string buffer;
|
||||||
|
assert(buffer.empty());
|
||||||
|
|
||||||
auto contentSize = ImGui::GetWindowContentRegionMax();
|
auto contentSize = ImGui::GetWindowContentRegionMax();
|
||||||
auto drawList = ImGui::GetWindowDrawList();
|
auto drawList = ImGui::GetWindowDrawList();
|
||||||
float longest(mTextStart);
|
float longest(mTextStart);
|
||||||
|
|
||||||
|
if (mScrollToTop)
|
||||||
|
{
|
||||||
|
mScrollToTop = false;
|
||||||
|
ImGui::SetScrollY(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
|
ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||||
auto scrollX = ImGui::GetScrollX();
|
auto scrollX = ImGui::GetScrollX();
|
||||||
auto scrollY = ImGui::GetScrollY();
|
auto scrollY = ImGui::GetScrollY();
|
||||||
@ -639,10 +671,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
Coordinates lineStartCoord(lineNo, 0);
|
Coordinates lineStartCoord(lineNo, 0);
|
||||||
Coordinates lineEndCoord(lineNo, (int)line.size());
|
Coordinates lineEndCoord(lineNo, (int)line.size());
|
||||||
|
|
||||||
/*
|
// Draw selection for the current line
|
||||||
Draw Selected area
|
|
||||||
*/
|
|
||||||
|
|
||||||
float sstart = -1.0f;
|
float sstart = -1.0f;
|
||||||
float ssend = -1.0f;
|
float ssend = -1.0f;
|
||||||
|
|
||||||
@ -662,10 +691,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
|
drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Draw breakpoints
|
||||||
Draw break point
|
|
||||||
*/
|
|
||||||
|
|
||||||
auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y);
|
auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y);
|
||||||
|
|
||||||
if (mBreakpoints.count(lineNo + 1) != 0)
|
if (mBreakpoints.count(lineNo + 1) != 0)
|
||||||
@ -674,10 +700,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::Breakpoint]);
|
drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::Breakpoint]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Draw error markers
|
||||||
Draw error marker
|
|
||||||
*/
|
|
||||||
|
|
||||||
auto errorIt = mErrorMarkers.find(lineNo + 1);
|
auto errorIt = mErrorMarkers.find(lineNo + 1);
|
||||||
if (errorIt != mErrorMarkers.end())
|
if (errorIt != mErrorMarkers.end())
|
||||||
{
|
{
|
||||||
@ -698,18 +721,12 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Draw line number (right aligned)
|
||||||
Draw line number (right aligned)
|
|
||||||
*/
|
|
||||||
|
|
||||||
snprintf(buf, 16, "%d ", lineNo + 1);
|
snprintf(buf, 16, "%d ", lineNo + 1);
|
||||||
auto lineNoWidth = ImGui::CalcTextSize(buf).x;
|
auto lineNoWidth = ImGui::CalcTextSize(buf).x;
|
||||||
drawList->AddText(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y), mPalette[(int)PaletteIndex::LineNumber], buf);
|
drawList->AddText(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y), mPalette[(int)PaletteIndex::LineNumber], buf);
|
||||||
|
|
||||||
/*
|
// Highlight the current line (where the cursor is)
|
||||||
Highlight the current line (where the cursor is).
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (mState.mCursorPosition.mLine == lineNo)
|
if (mState.mCursorPosition.mLine == lineNo)
|
||||||
{
|
{
|
||||||
auto focused = ImGui::IsWindowFocused();
|
auto focused = ImGui::IsWindowFocused();
|
||||||
@ -740,21 +757,18 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Render colorized text
|
||||||
Draw Text
|
auto prevColor = line.empty() ? mPalette[(int)PaletteIndex::Default] : GetGlyphColor(line[0]);
|
||||||
*/
|
|
||||||
|
|
||||||
auto prevColor = line.empty() ? PaletteIndex::Default : (line[0].mMultiLineComment ? PaletteIndex::MultiLineComment : line[0].mColorIndex);
|
|
||||||
ImVec2 bufferOffset;
|
ImVec2 bufferOffset;
|
||||||
|
|
||||||
for (auto& glyph : line)
|
for (auto& glyph : line)
|
||||||
{
|
{
|
||||||
auto color = glyph.mMultiLineComment ? PaletteIndex::MultiLineComment : glyph.mColorIndex;
|
auto color = GetGlyphColor(glyph);
|
||||||
|
|
||||||
if ((color != prevColor || glyph.mChar == '\t') && !buffer.empty())
|
if ((color != prevColor || glyph.mChar == '\t') && !buffer.empty())
|
||||||
{
|
{
|
||||||
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
||||||
drawList->AddText(newOffset, mPalette[(uint8_t)prevColor], buffer.c_str());
|
drawList->AddText(newOffset, prevColor, buffer.c_str());
|
||||||
auto textSize = ImGui::CalcTextSize(buffer.c_str());
|
auto textSize = ImGui::CalcTextSize(buffer.c_str());
|
||||||
bufferOffset.x += textSize.x + 1.0f * fontScale;
|
bufferOffset.x += textSize.x + 1.0f * fontScale;
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
@ -771,13 +785,14 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
if (!buffer.empty())
|
if (!buffer.empty())
|
||||||
{
|
{
|
||||||
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
||||||
drawList->AddText(newOffset, mPalette[(uint8_t)prevColor], buffer.c_str());
|
drawList->AddText(newOffset, prevColor, buffer.c_str());
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
++lineNo;
|
++lineNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw a tooltip on known identifiers/preprocessor symbols
|
||||||
if (ImGui::IsMousePosValid())
|
if (ImGui::IsMousePosValid())
|
||||||
{
|
{
|
||||||
auto id = GetWordAt(ScreenPosToCoordinates(ImGui::GetMousePos()));
|
auto id = GetWordAt(ScreenPosToCoordinates(ImGui::GetMousePos()));
|
||||||
@ -813,6 +828,23 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
ImGui::SetWindowFocus();
|
ImGui::SetWindowFocus();
|
||||||
mScrollToCursor = false;
|
mScrollToCursor = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
||||||
|
{
|
||||||
|
mWithinRender = true;
|
||||||
|
mTextChanged = false;
|
||||||
|
mCursorPositionChanged = false;
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, ImGui::ColorConvertU32ToFloat4(mPalette[(int)PaletteIndex::Background]));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::BeginChild(aTitle, aSize, aBorder, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NoMove);
|
||||||
|
ImGui::PushAllowKeyboardFocus(true);
|
||||||
|
|
||||||
|
HandleKeyboardInputs();
|
||||||
|
HandleMouseInputs();
|
||||||
|
ColorizeInternal();
|
||||||
|
Render();
|
||||||
|
|
||||||
ImGui::PopAllowKeyboardFocus();
|
ImGui::PopAllowKeyboardFocus();
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
@ -825,7 +857,7 @@ void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
|
|||||||
void TextEditor::SetText(const std::string & aText)
|
void TextEditor::SetText(const std::string & aText)
|
||||||
{
|
{
|
||||||
mLines.clear();
|
mLines.clear();
|
||||||
mLines.push_back(Line());
|
mLines.emplace_back(Line());
|
||||||
for (auto chr : aText)
|
for (auto chr : aText)
|
||||||
{
|
{
|
||||||
if (chr == '\r')
|
if (chr == '\r')
|
||||||
@ -833,16 +865,49 @@ void TextEditor::SetText(const std::string & aText)
|
|||||||
// ignore the carriage return character
|
// ignore the carriage return character
|
||||||
}
|
}
|
||||||
else if (chr == '\n')
|
else if (chr == '\n')
|
||||||
mLines.push_back(Line());
|
mLines.emplace_back(Line());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mLines.back().push_back(Glyph(chr, PaletteIndex::Default));
|
mLines.back().emplace_back(Glyph(chr, PaletteIndex::Default));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTextChanged = true;
|
mTextChanged = true;
|
||||||
}
|
mScrollToTop = true;
|
||||||
|
|
||||||
mUndoBuffer.clear();
|
mUndoBuffer.clear();
|
||||||
|
mUndoIndex = 0;
|
||||||
|
|
||||||
|
Colorize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditor::SetTextLines(const std::vector<std::string> & aLines)
|
||||||
|
{
|
||||||
|
mLines.clear();
|
||||||
|
|
||||||
|
if (aLines.empty())
|
||||||
|
{
|
||||||
|
mLines.emplace_back(Line());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLines.resize(aLines.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < aLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const std::string & aLine = aLines[i];
|
||||||
|
|
||||||
|
mLines[i].reserve(aLine.size());
|
||||||
|
for (size_t j = 0; j < aLine.size(); ++j)
|
||||||
|
mLines[i].emplace_back(Glyph(aLine[j], PaletteIndex::Default));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mTextChanged = true;
|
||||||
|
mScrollToTop = true;
|
||||||
|
|
||||||
|
mUndoBuffer.clear();
|
||||||
|
mUndoIndex = 0;
|
||||||
|
|
||||||
Colorize();
|
Colorize();
|
||||||
}
|
}
|
||||||
@ -869,7 +934,7 @@ void TextEditor::EnterCharacter(Char aChar, bool aShift)
|
|||||||
if (end.mColumn == 0 && end.mLine > 0)
|
if (end.mColumn == 0 && end.mLine > 0)
|
||||||
{
|
{
|
||||||
--end.mLine;
|
--end.mLine;
|
||||||
end.mColumn = mLines[end.mLine].size();
|
end.mColumn = (int)mLines[end.mLine].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
u.mRemovedStart = start;
|
u.mRemovedStart = start;
|
||||||
@ -883,14 +948,19 @@ void TextEditor::EnterCharacter(Char aChar, bool aShift)
|
|||||||
auto& line = mLines[i];
|
auto& line = mLines[i];
|
||||||
if (aShift)
|
if (aShift)
|
||||||
{
|
{
|
||||||
if (line[0].mChar == '\t')
|
if (line.empty() == false)
|
||||||
|
{
|
||||||
|
if (line.front().mChar == '\t')
|
||||||
{
|
{
|
||||||
line.erase(line.begin());
|
line.erase(line.begin());
|
||||||
if (i == end.mLine && end.mColumn > 0)
|
if (i == end.mLine && end.mColumn > 0)
|
||||||
end.mColumn--;
|
end.mColumn--;
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
else for (int j = 0; j < mTabSize && line[0].mChar == ' '; j++)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int j = 0; j < mTabSize && line.empty() == false && line.front().mChar == ' '; j++)
|
||||||
{
|
{
|
||||||
line.erase(line.begin());
|
line.erase(line.begin());
|
||||||
if (i == end.mLine && end.mColumn > 0)
|
if (i == end.mLine && end.mColumn > 0)
|
||||||
@ -898,6 +968,7 @@ void TextEditor::EnterCharacter(Char aChar, bool aShift)
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
line.insert(line.begin(), Glyph('\t', TextEditor::PaletteIndex::Background));
|
line.insert(line.begin(), Glyph('\t', TextEditor::PaletteIndex::Background));
|
||||||
@ -1027,7 +1098,7 @@ void TextEditor::SetSelection(const Coordinates & aStart, const Coordinates & aE
|
|||||||
case TextEditor::SelectionMode::Line:
|
case TextEditor::SelectionMode::Line:
|
||||||
{
|
{
|
||||||
const auto lineNo = mState.mSelectionEnd.mLine;
|
const auto lineNo = mState.mSelectionEnd.mLine;
|
||||||
const auto lineSize = lineNo < mLines.size() ? mLines[lineNo].size() : 0;
|
const auto lineSize = (size_t)lineNo < mLines.size() ? mLines[lineNo].size() : 0;
|
||||||
mState.mSelectionStart = Coordinates(mState.mSelectionStart.mLine, 0);
|
mState.mSelectionStart = Coordinates(mState.mSelectionStart.mLine, 0);
|
||||||
mState.mSelectionEnd = Coordinates(lineNo, (int)lineSize);
|
mState.mSelectionEnd = Coordinates(lineNo, (int)lineSize);
|
||||||
break;
|
break;
|
||||||
@ -1539,14 +1610,14 @@ void TextEditor::Redo(int aSteps)
|
|||||||
|
|
||||||
const TextEditor::Palette & TextEditor::GetDarkPalette()
|
const TextEditor::Palette & TextEditor::GetDarkPalette()
|
||||||
{
|
{
|
||||||
static Palette p = { {
|
const static Palette p = { {
|
||||||
0xffffffff, // None
|
0xff7f7f7f, // Default
|
||||||
0xffd69c56, // Keyword
|
0xffd69c56, // Keyword
|
||||||
0xff00ff00, // Number
|
0xff00ff00, // Number
|
||||||
0xff7070e0, // String
|
0xff7070e0, // String
|
||||||
0xff70a0e0, // Char literal
|
0xff70a0e0, // Char literal
|
||||||
0xffffffff, // Punctuation
|
0xffffffff, // Punctuation
|
||||||
0xff409090, // Preprocessor
|
0xff408080, // Preprocessor
|
||||||
0xffaaaaaa, // Identifier
|
0xffaaaaaa, // Identifier
|
||||||
0xff9bc64d, // Known identifier
|
0xff9bc64d, // Known identifier
|
||||||
0xffc040a0, // Preproc identifier
|
0xffc040a0, // Preproc identifier
|
||||||
@ -1567,14 +1638,14 @@ const TextEditor::Palette & TextEditor::GetDarkPalette()
|
|||||||
|
|
||||||
const TextEditor::Palette & TextEditor::GetLightPalette()
|
const TextEditor::Palette & TextEditor::GetLightPalette()
|
||||||
{
|
{
|
||||||
static Palette p = { {
|
const static Palette p = { {
|
||||||
0xff000000, // None
|
0xff7f7f7f, // None
|
||||||
0xffff0c06, // Keyword
|
0xffff0c06, // Keyword
|
||||||
0xff008000, // Number
|
0xff008000, // Number
|
||||||
0xff2020a0, // String
|
0xff2020a0, // String
|
||||||
0xff304070, // Char literal
|
0xff304070, // Char literal
|
||||||
0xff000000, // Punctuation
|
0xff000000, // Punctuation
|
||||||
0xff409090, // Preprocessor
|
0xff406060, // Preprocessor
|
||||||
0xff404040, // Identifier
|
0xff404040, // Identifier
|
||||||
0xff606010, // Known identifier
|
0xff606010, // Known identifier
|
||||||
0xffc040a0, // Preproc identifier
|
0xffc040a0, // Preproc identifier
|
||||||
@ -1595,7 +1666,7 @@ const TextEditor::Palette & TextEditor::GetLightPalette()
|
|||||||
|
|
||||||
const TextEditor::Palette & TextEditor::GetRetroBluePalette()
|
const TextEditor::Palette & TextEditor::GetRetroBluePalette()
|
||||||
{
|
{
|
||||||
static Palette p = { {
|
const static Palette p = { {
|
||||||
0xff00ffff, // None
|
0xff00ffff, // None
|
||||||
0xffffff00, // Keyword
|
0xffffff00, // Keyword
|
||||||
0xff00ff00, // Number
|
0xff00ff00, // Number
|
||||||
@ -1627,6 +1698,27 @@ std::string TextEditor::GetText() const
|
|||||||
return GetText(Coordinates(), Coordinates((int)mLines.size(), 0));
|
return GetText(Coordinates(), Coordinates((int)mLines.size(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> TextEditor::GetTextLines() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
result.reserve(mLines.size());
|
||||||
|
|
||||||
|
for (auto & line : mLines)
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
text.resize(line.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < line.size(); ++i)
|
||||||
|
text[i] = line[i].mChar;
|
||||||
|
|
||||||
|
result.emplace_back(std::move(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string TextEditor::GetSelectedText() const
|
std::string TextEditor::GetSelectedText() const
|
||||||
{
|
{
|
||||||
return GetText(mState.mSelectionStart, mState.mSelectionEnd);
|
return GetText(mState.mSelectionStart, mState.mSelectionEnd);
|
||||||
@ -1649,7 +1741,7 @@ void TextEditor::Colorize(int aFromLine, int aLines)
|
|||||||
mColorRangeMax = std::max(mColorRangeMax, toLine);
|
mColorRangeMax = std::max(mColorRangeMax, toLine);
|
||||||
mColorRangeMin = std::max(0, mColorRangeMin);
|
mColorRangeMin = std::max(0, mColorRangeMin);
|
||||||
mColorRangeMax = std::max(mColorRangeMin, mColorRangeMax);
|
mColorRangeMax = std::max(mColorRangeMin, mColorRangeMax);
|
||||||
mCheckMultilineComments = true;
|
mCheckComments = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::ColorizeRange(int aFromLine, int aToLine)
|
void TextEditor::ColorizeRange(int aFromLine, int aToLine)
|
||||||
@ -1664,7 +1756,6 @@ void TextEditor::ColorizeRange(int aFromLine, int aToLine)
|
|||||||
int endLine = std::max(0, std::min((int)mLines.size(), aToLine));
|
int endLine = std::max(0, std::min((int)mLines.size(), aToLine));
|
||||||
for (int i = aFromLine; i < endLine; ++i)
|
for (int i = aFromLine; i < endLine; ++i)
|
||||||
{
|
{
|
||||||
bool preproc = false;
|
|
||||||
auto& line = mLines[i];
|
auto& line = mLines[i];
|
||||||
|
|
||||||
if (line.empty())
|
if (line.empty())
|
||||||
@ -1733,7 +1824,7 @@ void TextEditor::ColorizeRange(int aFromLine, int aToLine)
|
|||||||
if (!mLanguageDefinition.mCaseSensitive)
|
if (!mLanguageDefinition.mCaseSensitive)
|
||||||
std::transform(id.begin(), id.end(), id.begin(), ::toupper);
|
std::transform(id.begin(), id.end(), id.begin(), ::toupper);
|
||||||
|
|
||||||
if (!preproc)
|
if (!line[first - bufferBegin].mPreprocessor)
|
||||||
{
|
{
|
||||||
if (mLanguageDefinition.mKeywords.count(id) != 0)
|
if (mLanguageDefinition.mKeywords.count(id) != 0)
|
||||||
token_color = PaletteIndex::Keyword;
|
token_color = PaletteIndex::Keyword;
|
||||||
@ -1746,16 +1837,10 @@ void TextEditor::ColorizeRange(int aFromLine, int aToLine)
|
|||||||
{
|
{
|
||||||
if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0)
|
if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0)
|
||||||
token_color = PaletteIndex::PreprocIdentifier;
|
token_color = PaletteIndex::PreprocIdentifier;
|
||||||
else
|
|
||||||
token_color = PaletteIndex::Identifier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (token_color == PaletteIndex::Preprocessor)
|
|
||||||
{
|
|
||||||
preproc = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < token_length; ++j)
|
for (size_t j = 0; j < token_length; ++j)
|
||||||
line[(token_begin - bufferBegin) + j].mColorIndex = token_color;
|
line[(token_begin - bufferBegin) + j].mColorIndex = token_color;
|
||||||
|
|
||||||
first = token_end;
|
first = token_end;
|
||||||
@ -1769,72 +1854,103 @@ void TextEditor::ColorizeInternal()
|
|||||||
if (mLines.empty())
|
if (mLines.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mCheckMultilineComments)
|
if (mCheckComments)
|
||||||
{
|
{
|
||||||
auto end = Coordinates((int)mLines.size(), 0);
|
auto end = Coordinates((int)mLines.size(), 0);
|
||||||
auto commentStart = end;
|
auto commentStart = end;
|
||||||
auto withinString = false;
|
auto withinString = false;
|
||||||
for (auto i = Coordinates(0, 0); i < end; Advance(i))
|
auto withinSingleLineComment = false;
|
||||||
|
auto withinPreproc = false;
|
||||||
|
auto firstChar = true; // there is no other non-whitespace characters in the line before
|
||||||
|
auto concatenate = false; // '\' on the very end of the line
|
||||||
|
|
||||||
|
for (auto currentCoord = Coordinates(0, 0); currentCoord < end; Advance(currentCoord))
|
||||||
{
|
{
|
||||||
auto& line = mLines[i.mLine];
|
auto& line = mLines[currentCoord.mLine];
|
||||||
|
|
||||||
|
if (currentCoord.mColumn == 0 && !concatenate)
|
||||||
|
{
|
||||||
|
withinSingleLineComment = false;
|
||||||
|
withinPreproc = false;
|
||||||
|
firstChar = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
concatenate = false;
|
||||||
|
|
||||||
if (!line.empty())
|
if (!line.empty())
|
||||||
{
|
{
|
||||||
auto& g = line[i.mColumn];
|
auto& g = line[currentCoord.mColumn];
|
||||||
auto c = g.mChar;
|
auto c = g.mChar;
|
||||||
|
|
||||||
bool inComment = commentStart <= i;
|
if (c != mLanguageDefinition.mPreprocChar && !isspace(c))
|
||||||
|
firstChar = false;
|
||||||
|
|
||||||
|
if (currentCoord.mColumn == line.size() - 1 && line[line.size() - 1].mChar == '\\')
|
||||||
|
concatenate = true;
|
||||||
|
|
||||||
|
bool inComment = commentStart <= currentCoord;
|
||||||
|
|
||||||
if (withinString)
|
if (withinString)
|
||||||
{
|
{
|
||||||
line[i.mColumn].mMultiLineComment = inComment;
|
line[currentCoord.mColumn].mMultiLineComment = inComment;
|
||||||
|
|
||||||
if (c == '\"')
|
if (c == '\"')
|
||||||
{
|
{
|
||||||
if (i.mColumn + 1 < (int)line.size() && line[i.mColumn + 1].mChar == '\"')
|
if (currentCoord.mColumn + 1 < (int)line.size() && line[currentCoord.mColumn + 1].mChar == '\"')
|
||||||
{
|
{
|
||||||
Advance(i);
|
Advance(currentCoord);
|
||||||
if (i.mColumn < (int)line.size())
|
if (currentCoord.mColumn < (int)line.size())
|
||||||
line[i.mColumn].mMultiLineComment = inComment;
|
line[currentCoord.mColumn].mMultiLineComment = inComment;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
withinString = false;
|
withinString = false;
|
||||||
}
|
}
|
||||||
else if (c == '\\')
|
else if (c == '\\')
|
||||||
{
|
{
|
||||||
Advance(i);
|
Advance(currentCoord);
|
||||||
if (i.mColumn < (int)line.size())
|
if (currentCoord.mColumn < (int)line.size())
|
||||||
line[i.mColumn].mMultiLineComment = inComment;
|
line[currentCoord.mColumn].mMultiLineComment = inComment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (firstChar && c == mLanguageDefinition.mPreprocChar)
|
||||||
|
withinPreproc = true;
|
||||||
|
|
||||||
if (c == '\"')
|
if (c == '\"')
|
||||||
{
|
{
|
||||||
withinString = true;
|
withinString = true;
|
||||||
line[i.mColumn].mMultiLineComment = inComment;
|
line[currentCoord.mColumn].mMultiLineComment = inComment;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto pred = [](const char& a, const Glyph& b) { return a == b.mChar; };
|
auto pred = [](const char& a, const Glyph& b) { return a == b.mChar; };
|
||||||
auto from = line.begin() + i.mColumn;
|
auto from = line.begin() + currentCoord.mColumn;
|
||||||
auto& startStr = mLanguageDefinition.mCommentStart;
|
auto& startStr = mLanguageDefinition.mCommentStart;
|
||||||
if (i.mColumn + startStr.size() <= line.size() &&
|
auto& singleStartStr = mLanguageDefinition.mSingleLineComment;
|
||||||
|
if (singleStartStr.size() > 0 &&
|
||||||
|
currentCoord.mColumn + singleStartStr.size() <= line.size() &&
|
||||||
|
equals(singleStartStr.begin(), singleStartStr.end(), from, from + singleStartStr.size(), pred))
|
||||||
|
withinSingleLineComment = true;
|
||||||
|
else if (!withinSingleLineComment && currentCoord.mColumn + startStr.size() <= line.size() &&
|
||||||
equals(startStr.begin(), startStr.end(), from, from + startStr.size(), pred))
|
equals(startStr.begin(), startStr.end(), from, from + startStr.size(), pred))
|
||||||
commentStart = i;
|
commentStart = currentCoord;
|
||||||
|
|
||||||
inComment = commentStart <= i;
|
inComment = commentStart <= currentCoord;
|
||||||
|
|
||||||
line[i.mColumn].mMultiLineComment = inComment;
|
line[currentCoord.mColumn].mMultiLineComment = inComment;
|
||||||
|
line[currentCoord.mColumn].mComment = withinSingleLineComment;
|
||||||
|
|
||||||
auto& endStr = mLanguageDefinition.mCommentEnd;
|
auto& endStr = mLanguageDefinition.mCommentEnd;
|
||||||
if (i.mColumn + 1 >= (int)endStr.size() &&
|
if (currentCoord.mColumn + 1 >= (int)endStr.size() &&
|
||||||
equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(), from + 1, pred))
|
equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(), from + 1, pred))
|
||||||
commentStart = end;
|
commentStart = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
line[currentCoord.mColumn].mPreprocessor = withinPreproc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mCheckMultilineComments = false;
|
mCheckComments = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1978,49 +2094,6 @@ void TextEditor::UndoRecord::Redo(TextEditor * aEditor)
|
|||||||
aEditor->EnsureCursorVisible();
|
aEditor->EnsureCursorVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TokenizeCStyleComment(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
|
||||||
{
|
|
||||||
if (*in_begin != '/')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (in_begin + 1 < in_end && in_begin[1] == '/')
|
|
||||||
{
|
|
||||||
out_begin = in_begin;
|
|
||||||
out_end = in_end;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool TokenizeCStylePreprocessorDirective(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
|
||||||
{
|
|
||||||
if (*in_begin != '#')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const char * p = in_begin + 1;
|
|
||||||
|
|
||||||
while (p < in_end && isblank(*p))
|
|
||||||
p++;
|
|
||||||
|
|
||||||
bool hasText = false;
|
|
||||||
|
|
||||||
while (p < in_end && ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_'))
|
|
||||||
{
|
|
||||||
hasText = true;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasText)
|
|
||||||
{
|
|
||||||
out_begin = in_begin;
|
|
||||||
out_end = p;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
static bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
||||||
{
|
{
|
||||||
const char * p = in_begin;
|
const char * p = in_begin;
|
||||||
@ -2202,6 +2275,8 @@ static bool TokenizeCStyleNumber(const char * in_begin, const char * in_end, con
|
|||||||
|
|
||||||
static bool TokenizeCStylePunctuation(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
static bool TokenizeCStylePunctuation(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
|
||||||
{
|
{
|
||||||
|
(void)in_end;
|
||||||
|
|
||||||
switch (*in_begin)
|
switch (*in_begin)
|
||||||
{
|
{
|
||||||
case '[':
|
case '[':
|
||||||
@ -2277,10 +2352,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus(
|
|||||||
out_end = in_end;
|
out_end = in_end;
|
||||||
paletteIndex = PaletteIndex::Default;
|
paletteIndex = PaletteIndex::Default;
|
||||||
}
|
}
|
||||||
else if (TokenizeCStyleComment(in_begin, in_end, out_begin, out_end))
|
|
||||||
paletteIndex = PaletteIndex::Comment;
|
|
||||||
else if (TokenizeCStylePreprocessorDirective(in_begin, in_end, out_begin, out_end))
|
|
||||||
paletteIndex = PaletteIndex::Preprocessor;
|
|
||||||
else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
|
else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
|
||||||
paletteIndex = PaletteIndex::String;
|
paletteIndex = PaletteIndex::String;
|
||||||
else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
|
else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
|
||||||
@ -2297,6 +2368,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus(
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = true;
|
langDef.mAutoIndentation = true;
|
||||||
@ -2356,7 +2428,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL()
|
|||||||
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("//.*", PaletteIndex::Comment));
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
|
||||||
@ -2369,6 +2440,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL()
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = true;
|
langDef.mAutoIndentation = true;
|
||||||
@ -2405,7 +2477,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL()
|
|||||||
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("//.*", PaletteIndex::Comment));
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
|
||||||
@ -2418,6 +2489,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL()
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = true;
|
langDef.mAutoIndentation = true;
|
||||||
@ -2467,10 +2539,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C()
|
|||||||
out_end = in_end;
|
out_end = in_end;
|
||||||
paletteIndex = PaletteIndex::Default;
|
paletteIndex = PaletteIndex::Default;
|
||||||
}
|
}
|
||||||
else if (TokenizeCStyleComment(in_begin, in_end, out_begin, out_end))
|
|
||||||
paletteIndex = PaletteIndex::Comment;
|
|
||||||
else if (TokenizeCStylePreprocessorDirective(in_begin, in_end, out_begin, out_end))
|
|
||||||
paletteIndex = PaletteIndex::Preprocessor;
|
|
||||||
else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
|
else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
|
||||||
paletteIndex = PaletteIndex::String;
|
paletteIndex = PaletteIndex::String;
|
||||||
else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
|
else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
|
||||||
@ -2487,6 +2555,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C()
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = true;
|
langDef.mAutoIndentation = true;
|
||||||
@ -2539,7 +2608,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL()
|
|||||||
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\-\\-.*", PaletteIndex::Comment));
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
|
||||||
@ -2551,6 +2619,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL()
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = false;
|
langDef.mCaseSensitive = false;
|
||||||
langDef.mAutoIndentation = false;
|
langDef.mAutoIndentation = false;
|
||||||
@ -2589,7 +2658,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScrip
|
|||||||
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("//.*", PaletteIndex::Comment));
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
|
||||||
@ -2601,6 +2669,7 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScrip
|
|||||||
|
|
||||||
langDef.mCommentStart = "/*";
|
langDef.mCommentStart = "/*";
|
||||||
langDef.mCommentEnd = "*/";
|
langDef.mCommentEnd = "*/";
|
||||||
|
langDef.mSingleLineComment = "//";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = true;
|
langDef.mAutoIndentation = true;
|
||||||
@ -2644,7 +2713,6 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua()
|
|||||||
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\-\\-.*", PaletteIndex::Comment));
|
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
|
||||||
@ -2653,8 +2721,9 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua()
|
|||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
|
||||||
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
|
langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
|
||||||
|
|
||||||
langDef.mCommentStart = "\\-\\-\\[\\[";
|
langDef.mCommentStart = "--[[";
|
||||||
langDef.mCommentEnd = "\\]\\]";
|
langDef.mCommentEnd = "]]";
|
||||||
|
langDef.mSingleLineComment = "--";
|
||||||
|
|
||||||
langDef.mCaseSensitive = true;
|
langDef.mCaseSensitive = true;
|
||||||
langDef.mAutoIndentation = false;
|
langDef.mAutoIndentation = false;
|
||||||
|
@ -134,9 +134,12 @@ public:
|
|||||||
{
|
{
|
||||||
Char mChar;
|
Char mChar;
|
||||||
PaletteIndex mColorIndex = PaletteIndex::Default;
|
PaletteIndex mColorIndex = PaletteIndex::Default;
|
||||||
|
bool mComment : 1;
|
||||||
bool mMultiLineComment : 1;
|
bool mMultiLineComment : 1;
|
||||||
|
bool mPreprocessor : 1;
|
||||||
|
|
||||||
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), mMultiLineComment(false) {}
|
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex),
|
||||||
|
mComment(false), mMultiLineComment(false), mPreprocessor(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Glyph> Line;
|
typedef std::vector<Glyph> Line;
|
||||||
@ -152,7 +155,8 @@ public:
|
|||||||
Keywords mKeywords;
|
Keywords mKeywords;
|
||||||
Identifiers mIdentifiers;
|
Identifiers mIdentifiers;
|
||||||
Identifiers mPreprocIdentifiers;
|
Identifiers mPreprocIdentifiers;
|
||||||
std::string mCommentStart, mCommentEnd;
|
std::string mCommentStart, mCommentEnd, mSingleLineComment;
|
||||||
|
char mPreprocChar;
|
||||||
bool mAutoIndentation;
|
bool mAutoIndentation;
|
||||||
|
|
||||||
TokenizeCallback mTokenize;
|
TokenizeCallback mTokenize;
|
||||||
@ -162,7 +166,7 @@ public:
|
|||||||
bool mCaseSensitive;
|
bool mCaseSensitive;
|
||||||
|
|
||||||
LanguageDefinition()
|
LanguageDefinition()
|
||||||
: mTokenize(nullptr)
|
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +185,7 @@ public:
|
|||||||
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
||||||
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
|
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
|
||||||
|
|
||||||
const Palette& GetPalette() const { return mPalette; }
|
const Palette& GetPalette() const { return mPaletteBase; }
|
||||||
void SetPalette(const Palette& aValue);
|
void SetPalette(const Palette& aValue);
|
||||||
|
|
||||||
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
||||||
@ -189,7 +193,9 @@ public:
|
|||||||
|
|
||||||
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
||||||
void SetText(const std::string& aText);
|
void SetText(const std::string& aText);
|
||||||
|
void SetTextLines(const std::vector<std::string>& aLines);
|
||||||
std::string GetText() const;
|
std::string GetText() const;
|
||||||
|
std::vector<std::string> GetTextLines() const;
|
||||||
std::string GetSelectedText() const;
|
std::string GetSelectedText() const;
|
||||||
std::string GetCurrentLineText()const;
|
std::string GetCurrentLineText()const;
|
||||||
|
|
||||||
@ -309,6 +315,11 @@ private:
|
|||||||
void DeleteSelection();
|
void DeleteSelection();
|
||||||
std::string GetWordUnderCursor() const;
|
std::string GetWordUnderCursor() const;
|
||||||
std::string GetWordAt(const Coordinates& aCoords) const;
|
std::string GetWordAt(const Coordinates& aCoords) const;
|
||||||
|
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
|
||||||
|
|
||||||
|
void HandleKeyboardInputs();
|
||||||
|
void HandleMouseInputs();
|
||||||
|
void Render();
|
||||||
|
|
||||||
float mLineSpacing;
|
float mLineSpacing;
|
||||||
Lines mLines;
|
Lines mLines;
|
||||||
@ -321,6 +332,7 @@ private:
|
|||||||
bool mReadOnly;
|
bool mReadOnly;
|
||||||
bool mWithinRender;
|
bool mWithinRender;
|
||||||
bool mScrollToCursor;
|
bool mScrollToCursor;
|
||||||
|
bool mScrollToTop;
|
||||||
bool mTextChanged;
|
bool mTextChanged;
|
||||||
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
|
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
|
||||||
int mLeftMargin;
|
int mLeftMargin;
|
||||||
@ -328,15 +340,18 @@ private:
|
|||||||
int mColorRangeMin, mColorRangeMax;
|
int mColorRangeMin, mColorRangeMax;
|
||||||
SelectionMode mSelectionMode;
|
SelectionMode mSelectionMode;
|
||||||
|
|
||||||
|
Palette mPaletteBase;
|
||||||
Palette mPalette;
|
Palette mPalette;
|
||||||
LanguageDefinition mLanguageDefinition;
|
LanguageDefinition mLanguageDefinition;
|
||||||
RegexList mRegexList;
|
RegexList mRegexList;
|
||||||
|
|
||||||
bool mCheckMultilineComments;
|
bool mCheckComments;
|
||||||
Breakpoints mBreakpoints;
|
Breakpoints mBreakpoints;
|
||||||
ErrorMarkers mErrorMarkers;
|
ErrorMarkers mErrorMarkers;
|
||||||
ImVec2 mCharAdvance;
|
ImVec2 mCharAdvance;
|
||||||
Coordinates mInteractiveStart, mInteractiveEnd;
|
Coordinates mInteractiveStart, mInteractiveEnd;
|
||||||
|
|
||||||
|
float mLastClick;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
|
// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
|
||||||
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||||
// Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut
|
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained and v0.60+ by @ocornut.
|
||||||
|
|
||||||
// Changelog:
|
// Changelog:
|
||||||
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
||||||
@ -10,6 +10,7 @@
|
|||||||
// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member
|
// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member
|
||||||
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
||||||
// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX
|
// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX
|
||||||
|
// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
|
||||||
|
|
||||||
// Gamma Correct Blending:
|
// Gamma Correct Blending:
|
||||||
// FreeType assumes blending in linear space rather than gamma space.
|
// FreeType assumes blending in linear space rather than gamma space.
|
||||||
@ -17,18 +18,16 @@
|
|||||||
// For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
// For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||||
// The default imgui styles will be impacted by this change (alpha values will need tweaking).
|
// The default imgui styles will be impacted by this change (alpha values will need tweaking).
|
||||||
|
|
||||||
// TODO:
|
// FIXME: FreeType's memory allocator is not overridden.
|
||||||
// - Output texture has excessive resolution (lots of vertical waste).
|
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
|
||||||
// - FreeType's memory allocator is not overridden.
|
|
||||||
// - cfg.OversampleH, OversampleV are ignored (but perhaps not so necessary with this rasterizer).
|
|
||||||
|
|
||||||
#include "imgui_freetype.h"
|
#include "imgui_freetype.h"
|
||||||
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H // <freetype/freetype.h>
|
||||||
#include FT_GLYPH_H
|
#include FT_GLYPH_H // <freetype/ftglyph.h>
|
||||||
#include FT_SYNTHESIS_H
|
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||||
@ -74,10 +73,10 @@ namespace
|
|||||||
/// A structure that describe a glyph.
|
/// A structure that describe a glyph.
|
||||||
struct GlyphInfo
|
struct GlyphInfo
|
||||||
{
|
{
|
||||||
float Width; // Glyph's width in pixels.
|
int Width; // Glyph's width in pixels.
|
||||||
float Height; // Glyph's height in pixels.
|
int Height; // Glyph's height in pixels.
|
||||||
float OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
||||||
float OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
||||||
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,82 +95,80 @@ namespace
|
|||||||
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||||
struct FreeTypeFont
|
struct FreeTypeFont
|
||||||
{
|
{
|
||||||
bool Init(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||||
void Shutdown();
|
void CloseFont();
|
||||||
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||||
|
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||||
bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap);
|
const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
|
||||||
void BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
|
void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
|
||||||
|
~FreeTypeFont() { CloseFont(); }
|
||||||
|
|
||||||
// [Internals]
|
// [Internals]
|
||||||
FontInfo Info; // Font descriptor of the current font.
|
FontInfo Info; // Font descriptor of the current font.
|
||||||
|
FT_Face Face;
|
||||||
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
||||||
FT_Library FreetypeLibrary;
|
FT_Int32 LoadFlags;
|
||||||
FT_Face FreetypeFace;
|
|
||||||
FT_Int32 FreetypeLoadFlags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// From SDL_ttf: Handy routines for converting from fixed point
|
// From SDL_ttf: Handy routines for converting from fixed point
|
||||||
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
||||||
|
|
||||||
bool FreeTypeFont::Init(const ImFontConfig& cfg, unsigned int extra_user_flags)
|
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags)
|
||||||
{
|
{
|
||||||
// FIXME: substitute allocator
|
// FIXME: substitute allocator
|
||||||
FT_Error error = FT_Init_FreeType(&FreetypeLibrary);
|
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return false;
|
return false;
|
||||||
error = FT_New_Memory_Face(FreetypeLibrary, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &FreetypeFace);
|
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||||
if (error != 0)
|
|
||||||
return false;
|
|
||||||
error = FT_Select_Charmap(FreetypeFace, FT_ENCODING_UNICODE);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset(&Info, 0, sizeof(Info));
|
memset(&Info, 0, sizeof(Info));
|
||||||
SetPixelHeight((uint32_t)cfg.SizePixels);
|
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||||
|
|
||||||
// Convert to freetype flags (nb: Bold and Oblique are processed separately)
|
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||||
UserFlags = cfg.RasterizerFlags | extra_user_flags;
|
UserFlags = cfg.RasterizerFlags | extra_user_flags;
|
||||||
FreetypeLoadFlags = FT_LOAD_NO_BITMAP;
|
LoadFlags = FT_LOAD_NO_BITMAP;
|
||||||
if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING;
|
if (UserFlags & ImGuiFreeType::NoHinting)
|
||||||
if (UserFlags & ImGuiFreeType::NoAutoHint) FreetypeLoadFlags |= FT_LOAD_NO_AUTOHINT;
|
LoadFlags |= FT_LOAD_NO_HINTING;
|
||||||
if (UserFlags & ImGuiFreeType::ForceAutoHint) FreetypeLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
if (UserFlags & ImGuiFreeType::NoAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||||
|
if (UserFlags & ImGuiFreeType::ForceAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||||
if (UserFlags & ImGuiFreeType::LightHinting)
|
if (UserFlags & ImGuiFreeType::LightHinting)
|
||||||
FreetypeLoadFlags |= FT_LOAD_TARGET_LIGHT;
|
LoadFlags |= FT_LOAD_TARGET_LIGHT;
|
||||||
else if (UserFlags & ImGuiFreeType::MonoHinting)
|
else if (UserFlags & ImGuiFreeType::MonoHinting)
|
||||||
FreetypeLoadFlags |= FT_LOAD_TARGET_MONO;
|
LoadFlags |= FT_LOAD_TARGET_MONO;
|
||||||
else
|
else
|
||||||
FreetypeLoadFlags |= FT_LOAD_TARGET_NORMAL;
|
LoadFlags |= FT_LOAD_TARGET_NORMAL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeTypeFont::Shutdown()
|
void FreeTypeFont::CloseFont()
|
||||||
{
|
{
|
||||||
if (FreetypeFace)
|
if (Face)
|
||||||
{
|
{
|
||||||
FT_Done_Face(FreetypeFace);
|
FT_Done_Face(Face);
|
||||||
FreetypeFace = NULL;
|
Face = NULL;
|
||||||
FT_Done_FreeType(FreetypeLibrary);
|
|
||||||
FreetypeLibrary = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
||||||
{
|
{
|
||||||
// I'm not sure how to deal with font sizes properly.
|
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
|
||||||
// As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph,
|
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
||||||
// i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
|
||||||
FT_Size_RequestRec req;
|
FT_Size_RequestRec req;
|
||||||
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||||
req.width = 0;
|
req.width = 0;
|
||||||
req.height = (uint32_t)pixel_height * 64;
|
req.height = (uint32_t)pixel_height * 64;
|
||||||
req.horiResolution = 0;
|
req.horiResolution = 0;
|
||||||
req.vertResolution = 0;
|
req.vertResolution = 0;
|
||||||
FT_Request_Size(FreetypeFace, &req);
|
FT_Request_Size(Face, &req);
|
||||||
|
|
||||||
// update font info
|
// Update font info
|
||||||
FT_Size_Metrics metrics = FreetypeFace->size->metrics;
|
FT_Size_Metrics metrics = Face->size->metrics;
|
||||||
Info.PixelHeight = (uint32_t)pixel_height;
|
Info.PixelHeight = (uint32_t)pixel_height;
|
||||||
Info.Ascender = (float)FT_CEIL(metrics.ascender);
|
Info.Ascender = (float)FT_CEIL(metrics.ascender);
|
||||||
Info.Descender = (float)FT_CEIL(metrics.descender);
|
Info.Descender = (float)FT_CEIL(metrics.descender);
|
||||||
@ -180,52 +177,58 @@ namespace
|
|||||||
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);
|
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo &glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap)
|
const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
|
||||||
{
|
{
|
||||||
uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint);
|
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
|
||||||
if (glyph_index == 0)
|
if (glyph_index == 0)
|
||||||
return false;
|
return NULL;
|
||||||
FT_Error error = FT_Load_Glyph(FreetypeFace, glyph_index, FreetypeLoadFlags);
|
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||||
if (error)
|
if (error)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
// Need an outline for this to work
|
// Need an outline for this to work
|
||||||
FT_GlyphSlot slot = FreetypeFace->glyph;
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
|
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
|
||||||
|
|
||||||
|
// Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
|
||||||
if (UserFlags & ImGuiFreeType::Bold)
|
if (UserFlags & ImGuiFreeType::Bold)
|
||||||
FT_GlyphSlot_Embolden(slot);
|
FT_GlyphSlot_Embolden(slot);
|
||||||
if (UserFlags & ImGuiFreeType::Oblique)
|
if (UserFlags & ImGuiFreeType::Oblique)
|
||||||
|
{
|
||||||
FT_GlyphSlot_Oblique(slot);
|
FT_GlyphSlot_Oblique(slot);
|
||||||
|
//FT_BBox bbox;
|
||||||
// Retrieve the glyph
|
//FT_Outline_Get_BBox(&slot->outline, &bbox);
|
||||||
error = FT_Get_Glyph(slot, &ft_glyph);
|
//slot->metrics.width = bbox.xMax - bbox.xMin;
|
||||||
if (error != 0)
|
//slot->metrics.height = bbox.yMax - bbox.yMin;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Rasterize
|
|
||||||
error = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, NULL, true);
|
|
||||||
if (error != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ft_bitmap = (FT_BitmapGlyph)ft_glyph;
|
|
||||||
glyph_info.AdvanceX = (float)FT_CEIL(slot->advance.x);
|
|
||||||
glyph_info.OffsetX = (float)ft_bitmap->left;
|
|
||||||
glyph_info.OffsetY = -(float)ft_bitmap->top;
|
|
||||||
glyph_info.Width = (float)ft_bitmap->bitmap.width;
|
|
||||||
glyph_info.Height = (float)ft_bitmap->bitmap.rows;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeTypeFont::BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
return &slot->metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
|
||||||
|
{
|
||||||
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
|
FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
|
||||||
|
if (error != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
|
||||||
|
out_glyph_info->Width = (int)ft_bitmap->width;
|
||||||
|
out_glyph_info->Height = (int)ft_bitmap->rows;
|
||||||
|
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
|
||||||
|
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
|
||||||
|
out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
|
||||||
|
|
||||||
|
return ft_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
||||||
{
|
{
|
||||||
IM_ASSERT(ft_bitmap != NULL);
|
IM_ASSERT(ft_bitmap != NULL);
|
||||||
|
const uint32_t w = ft_bitmap->width;
|
||||||
const uint32_t w = ft_bitmap->bitmap.width;
|
const uint32_t h = ft_bitmap->rows;
|
||||||
const uint32_t h = ft_bitmap->bitmap.rows;
|
const uint8_t* src = ft_bitmap->buffer;
|
||||||
const uint8_t* src = ft_bitmap->bitmap.buffer;
|
const uint32_t src_pitch = ft_bitmap->pitch;
|
||||||
const uint32_t src_pitch = ft_bitmap->bitmap.pitch;
|
|
||||||
|
|
||||||
if (multiply_table == NULL)
|
if (multiply_table == NULL)
|
||||||
{
|
{
|
||||||
@ -246,143 +249,332 @@ namespace
|
|||||||
#define STB_RECT_PACK_IMPLEMENTATION
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
#include "imstb_rectpack.h"
|
#include "imstb_rectpack.h"
|
||||||
|
|
||||||
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
|
struct ImFontBuildSrcGlyphFT
|
||||||
|
{
|
||||||
|
GlyphInfo Info;
|
||||||
|
uint32_t Codepoint;
|
||||||
|
unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImFontBuildSrcDataFT
|
||||||
|
{
|
||||||
|
FreeTypeFont Font;
|
||||||
|
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
||||||
|
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
||||||
|
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
||||||
|
int GlyphsHighest; // Highest requested codepoint
|
||||||
|
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
||||||
|
ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
||||||
|
ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
||||||
|
struct ImFontBuildDstDataFT
|
||||||
|
{
|
||||||
|
int SrcCount; // Number of source fonts targeting this destination font.
|
||||||
|
int GlyphsHighest;
|
||||||
|
int GlyphsCount;
|
||||||
|
ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||||
{
|
{
|
||||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||||
IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported
|
|
||||||
|
|
||||||
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
||||||
|
|
||||||
atlas->TexID = NULL;
|
// Clear atlas
|
||||||
|
atlas->TexID = (ImTextureID)NULL;
|
||||||
atlas->TexWidth = atlas->TexHeight = 0;
|
atlas->TexWidth = atlas->TexHeight = 0;
|
||||||
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||||
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||||
atlas->ClearTexData();
|
atlas->ClearTexData();
|
||||||
|
|
||||||
ImVector<FreeTypeFont> fonts;
|
// Temporary storage for building
|
||||||
fonts.resize(atlas->ConfigData.Size);
|
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||||
|
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||||
|
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||||
|
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||||
|
memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||||
|
memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||||
|
|
||||||
ImVec2 max_glyph_size(1.0f, 1.0f);
|
// 1. Initialize font loading structure, check font data validity
|
||||||
|
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||||
// Count glyphs/ranges, initialize font
|
|
||||||
int total_glyphs_count = 0;
|
|
||||||
int total_ranges_count = 0;
|
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
FreeTypeFont& font_face = fonts[input_i];
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
FreeTypeFont& font_face = src_tmp.Font;
|
||||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||||
|
|
||||||
if (!font_face.Init(cfg, extra_flags))
|
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||||
|
src_tmp.DstIndex = -1;
|
||||||
|
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||||
|
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||||
|
src_tmp.DstIndex = output_i;
|
||||||
|
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||||
|
if (src_tmp.DstIndex == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth);
|
// Load font
|
||||||
max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender);
|
if (!font_face.InitFont(ft_library, cfg, extra_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!cfg.GlyphRanges)
|
// Measure highest codepoints
|
||||||
cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++)
|
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||||
total_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||||
|
dst_tmp.SrcCount++;
|
||||||
|
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
|
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
||||||
// Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
int total_glyphs_count = 0;
|
||||||
atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
|
||||||
|
if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
|
||||||
|
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
|
||||||
|
|
||||||
// We don't do the original first pass to determine texture height, but just rough estimate.
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
// Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes.
|
for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
|
||||||
// Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the
|
{
|
||||||
// shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.)
|
if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
||||||
const int total_rects = total_glyphs_count + atlas->CustomRects.size();
|
continue;
|
||||||
float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f)));
|
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
|
||||||
float min_rects_per_column = ceilf(total_rects / min_rects_per_row);
|
if (glyph_index == 0)
|
||||||
atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f));
|
continue;
|
||||||
|
|
||||||
// Create texture
|
// Add to avail set/counters
|
||||||
|
src_tmp.GlyphsCount++;
|
||||||
|
dst_tmp.GlyphsCount++;
|
||||||
|
src_tmp.GlyphsSet.SetBit(codepoint, true);
|
||||||
|
if (dst_tmp.SrcCount > 1)
|
||||||
|
dst_tmp.GlyphsSet.SetBit(codepoint, true);
|
||||||
|
total_glyphs_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(int));
|
||||||
|
const int* it_begin = src_tmp.GlyphsSet.Storage.begin();
|
||||||
|
const int* it_end = src_tmp.GlyphsSet.Storage.end();
|
||||||
|
for (const int* it = it_begin; it < it_end; it++)
|
||||||
|
if (int entries_32 = *it)
|
||||||
|
for (int bit_n = 0; bit_n < 32; bit_n++)
|
||||||
|
if (entries_32 & (1 << bit_n))
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT src_glyph;
|
||||||
|
memset(&src_glyph, 0, sizeof(src_glyph));
|
||||||
|
src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
|
||||||
|
//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
|
||||||
|
src_tmp.GlyphsList.push_back(src_glyph);
|
||||||
|
}
|
||||||
|
src_tmp.GlyphsSet.Clear();
|
||||||
|
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
||||||
|
}
|
||||||
|
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
||||||
|
dst_tmp_array[dst_i].GlyphsSet.Clear();
|
||||||
|
dst_tmp_array.clear();
|
||||||
|
|
||||||
|
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
||||||
|
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
||||||
|
ImVector<stbrp_rect> buf_rects;
|
||||||
|
buf_rects.resize(total_glyphs_count);
|
||||||
|
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
||||||
|
|
||||||
|
// Allocate temporary rasterization data buffers.
|
||||||
|
// We could not find a way to retrieve accurate glyph size without rendering them.
|
||||||
|
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
|
||||||
|
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations.
|
||||||
|
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
|
||||||
|
int buf_bitmap_current_used_bytes = 0;
|
||||||
|
ImVector<unsigned char*> buf_bitmap_buffers;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
|
||||||
|
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
||||||
|
// 8. Render/rasterize font characters into the texture
|
||||||
|
int total_surface = 0;
|
||||||
|
int buf_rects_out_n = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
||||||
|
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||||
|
|
||||||
|
// Compute multiply table if requested
|
||||||
|
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||||
|
unsigned char multiply_table[256];
|
||||||
|
if (multiply_enabled)
|
||||||
|
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||||
|
|
||||||
|
// Gather the sizes of all rectangles we will need to pack
|
||||||
|
const int padding = atlas->TexGlyphPadding;
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
|
|
||||||
|
const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
|
||||||
|
IM_ASSERT(metrics != NULL);
|
||||||
|
if (metrics == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Render glyph into a bitmap (currently held by FreeType)
|
||||||
|
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
|
||||||
|
IM_ASSERT(ft_bitmap);
|
||||||
|
|
||||||
|
// Allocate new temporary chunk if needed
|
||||||
|
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height;
|
||||||
|
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
buf_bitmap_current_used_bytes = 0;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
|
||||||
|
src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes;
|
||||||
|
buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
|
||||||
|
src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL);
|
||||||
|
|
||||||
|
src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);
|
||||||
|
src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);
|
||||||
|
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need a width for the skyline algorithm, any width!
|
||||||
|
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||||
|
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
||||||
|
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
||||||
|
atlas->TexHeight = 0;
|
||||||
|
if (atlas->TexDesiredWidth > 0)
|
||||||
|
atlas->TexWidth = atlas->TexDesiredWidth;
|
||||||
|
else
|
||||||
|
atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
|
||||||
|
|
||||||
|
// 5. Start packing
|
||||||
|
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||||
|
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||||
|
const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
|
||||||
|
ImVector<stbrp_node> pack_nodes;
|
||||||
|
pack_nodes.resize(num_nodes_for_packing_algorithm);
|
||||||
|
stbrp_context pack_context;
|
||||||
|
stbrp_init_target(&pack_context, atlas->TexWidth, TEX_HEIGHT_MAX, pack_nodes.Data, pack_nodes.Size);
|
||||||
|
ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
|
||||||
|
|
||||||
|
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
||||||
|
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
if (src_tmp.Rects[glyph_i].was_packed)
|
||||||
|
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Allocate texture
|
||||||
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
||||||
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||||
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
||||||
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
|
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
|
||||||
|
|
||||||
// Start packing
|
// 8. Copy rasterized font characters back into the main texture
|
||||||
ImVector<stbrp_node> pack_nodes;
|
// 9. Setup ImFont and glyphs for runtime
|
||||||
pack_nodes.resize(total_rects);
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
stbrp_context context;
|
|
||||||
stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects);
|
|
||||||
|
|
||||||
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
|
||||||
ImFontAtlasBuildPackCustomRects(atlas, &context);
|
|
||||||
|
|
||||||
// Render characters, setup ImFont and glyphs for runtime
|
|
||||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
||||||
{
|
{
|
||||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
FreeTypeFont& font_face = fonts[input_i];
|
if (src_tmp.GlyphsCount == 0)
|
||||||
ImFont* dst_font = cfg.DstFont;
|
continue;
|
||||||
if (cfg.MergeMode)
|
|
||||||
dst_font->BuildLookupTable();
|
|
||||||
|
|
||||||
const float ascent = font_face.Info.Ascender;
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
const float descent = font_face.Info.Descender;
|
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
|
||||||
|
|
||||||
|
const float ascent = src_tmp.Font.Info.Ascender;
|
||||||
|
const float descent = src_tmp.Font.Info.Descender;
|
||||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||||
const float font_off_x = cfg.GlyphOffset.x;
|
const float font_off_x = cfg.GlyphOffset.x;
|
||||||
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
||||||
|
|
||||||
bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
const int padding = atlas->TexGlyphPadding;
|
||||||
unsigned char multiply_table[256];
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
if (multiply_enabled)
|
|
||||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
|
||||||
|
|
||||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
|
|
||||||
{
|
{
|
||||||
for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint)
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
{
|
stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
|
||||||
if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint))
|
IM_ASSERT(pack_rect.was_packed);
|
||||||
continue;
|
|
||||||
|
|
||||||
FT_Glyph ft_glyph = NULL;
|
GlyphInfo& info = src_glyph.Info;
|
||||||
FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph
|
IM_ASSERT(info.Width + padding <= pack_rect.w);
|
||||||
GlyphInfo glyph_info;
|
IM_ASSERT(info.Height + padding <= pack_rect.h);
|
||||||
if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap))
|
const int tx = pack_rect.x + padding;
|
||||||
continue;
|
const int ty = pack_rect.y + padding;
|
||||||
|
|
||||||
// Pack rectangle
|
// Blit from temporary buffer to final texture
|
||||||
stbrp_rect rect;
|
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
||||||
rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering
|
size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
||||||
rect.h = (uint16_t)glyph_info.Height + 1;
|
unsigned char* blit_src = src_glyph.BitmapData;
|
||||||
stbrp_pack_rects(&context, &rect, 1);
|
unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
|
||||||
|
for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||||
|
memcpy(blit_dst, blit_src, blit_src_stride);
|
||||||
|
|
||||||
// Copy rasterized pixels to main texture
|
float char_advance_x_org = info.AdvanceX;
|
||||||
uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x;
|
|
||||||
font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL);
|
|
||||||
FT_Done_Glyph(ft_glyph);
|
|
||||||
|
|
||||||
float char_advance_x_org = glyph_info.AdvanceX;
|
|
||||||
float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
||||||
float char_off_x = font_off_x;
|
float char_off_x = font_off_x;
|
||||||
if (char_advance_x_org != char_advance_x_mod)
|
if (char_advance_x_org != char_advance_x_mod)
|
||||||
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
||||||
|
|
||||||
// Register glyph
|
// Register glyph
|
||||||
dst_font->AddGlyph((ImWchar)codepoint,
|
float x0 = info.OffsetX + char_off_x;
|
||||||
glyph_info.OffsetX + char_off_x,
|
float y0 = info.OffsetY + font_off_y;
|
||||||
glyph_info.OffsetY + font_off_y,
|
float x1 = x0 + info.Width;
|
||||||
glyph_info.OffsetX + char_off_x + glyph_info.Width,
|
float y1 = y0 + info.Height;
|
||||||
glyph_info.OffsetY + font_off_y + glyph_info.Height,
|
float u0 = (tx) / (float)atlas->TexWidth;
|
||||||
rect.x / (float)atlas->TexWidth,
|
float v0 = (ty) / (float)atlas->TexHeight;
|
||||||
rect.y / (float)atlas->TexHeight,
|
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||||
(rect.x + glyph_info.Width) / (float)atlas->TexWidth,
|
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||||
(rect.y + glyph_info.Height) / (float)atlas->TexHeight,
|
dst_font->AddGlyph((ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, char_advance_x_mod);
|
||||||
char_advance_x_mod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
src_tmp.Rects = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
for (int n = 0; n < fonts.Size; n++)
|
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
||||||
fonts[n].Shutdown();
|
ImGui::MemFree(buf_bitmap_buffers[buf_i]);
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
src_tmp_array[src_i].~ImFontBuildSrcDataFT();
|
||||||
|
|
||||||
ImFontAtlasBuildFinish(atlas);
|
ImFontAtlasBuildFinish(atlas);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
|
||||||
|
{
|
||||||
|
FT_Library ft_library;
|
||||||
|
FT_Error error = FT_Init_FreeType(&ft_library);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags);
|
||||||
|
FT_Done_FreeType(ft_library);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
|
// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
|
||||||
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||||
// Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut
|
// Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// ImGui Platform Binding for: GLFW
|
// dear imgui: Platform Binding for GLFW
|
||||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
// (Requires: GLFW 3.1+)
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Platform: Clipboard support.
|
// [X] Platform: Clipboard support.
|
||||||
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
@ -14,6 +15,8 @@
|
|||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||||
@ -57,6 +60,12 @@ static double g_Time = 0.0;
|
|||||||
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
|
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
|
||||||
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
|
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
|
||||||
|
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
|
||||||
|
static GLFWcharfun g_PrevUserCallbackChar = NULL;
|
||||||
|
|
||||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||||
{
|
{
|
||||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||||
@ -67,49 +76,53 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
|||||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/)
|
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
{
|
{
|
||||||
|
if (g_PrevUserCallbackMousebutton != NULL)
|
||||||
|
g_PrevUserCallbackMousebutton(window, button, action, mods);
|
||||||
|
|
||||||
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
||||||
g_MouseJustPressed[button] = true;
|
g_MouseJustPressed[button] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double xoffset, double yoffset)
|
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||||
{
|
{
|
||||||
|
if (g_PrevUserCallbackScroll != NULL)
|
||||||
|
g_PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.MouseWheelH += (float)xoffset;
|
io.MouseWheelH += (float)xoffset;
|
||||||
io.MouseWheel += (float)yoffset;
|
io.MouseWheel += (float)yoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
|
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
{
|
{
|
||||||
|
if (g_PrevUserCallbackKey != NULL)
|
||||||
|
g_PrevUserCallbackKey(window, key, scancode, action, mods);
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if (action == GLFW_PRESS)
|
if (action == GLFW_PRESS)
|
||||||
io.KeysDown[key] = true;
|
io.KeysDown[key] = true;
|
||||||
if (action == GLFW_RELEASE)
|
if (action == GLFW_RELEASE)
|
||||||
io.KeysDown[key] = false;
|
io.KeysDown[key] = false;
|
||||||
|
|
||||||
(void)mods; // Modifiers are not reliable across systems
|
// Modifiers are not reliable across systems
|
||||||
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||||
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||||
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||||
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)
|
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||||
{
|
{
|
||||||
|
if (g_PrevUserCallbackChar != NULL)
|
||||||
|
g_PrevUserCallbackChar(window, c);
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if (c > 0 && c < 0x10000)
|
if (c > 0 && c < 0x10000)
|
||||||
io.AddInputCharacter((unsigned short)c);
|
io.AddInputCharacter((unsigned short)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
|
||||||
{
|
|
||||||
glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
|
||||||
glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
|
||||||
glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
|
||||||
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||||
{
|
{
|
||||||
g_Window = window;
|
g_Window = window;
|
||||||
@ -119,6 +132,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
|||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_glfw";
|
||||||
|
|
||||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||||
@ -159,8 +173,18 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
|||||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
|
||||||
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
g_PrevUserCallbackScroll = NULL;
|
||||||
|
g_PrevUserCallbackKey = NULL;
|
||||||
|
g_PrevUserCallbackChar = NULL;
|
||||||
if (install_callbacks)
|
if (install_callbacks)
|
||||||
ImGui_ImplGlfw_InstallCallbacks(window);
|
{
|
||||||
|
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||||
|
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||||
|
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||||
|
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||||
|
}
|
||||||
|
|
||||||
g_ClientApi = client_api;
|
g_ClientApi = client_api;
|
||||||
return true;
|
return true;
|
||||||
@ -244,9 +268,9 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
|
|||||||
void ImGui_ImplGlfw_NewFrame()
|
void ImGui_ImplGlfw_NewFrame()
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
// Setup display size
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
int w, h;
|
int w, h;
|
||||||
int display_w, display_h;
|
int display_w, display_h;
|
||||||
glfwGetWindowSize(g_Window, &w, &h);
|
glfwGetWindowSize(g_Window, &w, &h);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// ImGui Platform Binding for: GLFW
|
// dear imgui: Platform Binding for GLFW
|
||||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Platform: Clipboard support.
|
// [X] Platform: Clipboard support.
|
||||||
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
@ -16,6 +16,8 @@
|
|||||||
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||||
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||||
@ -23,9 +25,8 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool in
|
|||||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||||
|
|
||||||
// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
|
// InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any.
|
||||||
// Provided here if you want to chain callbacks.
|
// InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks.
|
||||||
// You can also handle inputs yourself and use those as a reference.
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// ImGui Renderer for: OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
|
// dear imgui: Renderer for OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
|
||||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||||
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
||||||
|
|
||||||
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT).
|
||||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||||
@ -99,6 +101,9 @@ static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
|||||||
// Functions
|
// Functions
|
||||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
{
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl3";
|
||||||
|
|
||||||
// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||||
#ifdef USE_GL_ES3
|
#ifdef USE_GL_ES3
|
||||||
if (glsl_version == NULL)
|
if (glsl_version == NULL)
|
||||||
@ -110,6 +115,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
|||||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
||||||
strcpy(g_GlslVersionString, glsl_version);
|
strcpy(g_GlslVersionString, glsl_version);
|
||||||
strcat(g_GlslVersionString, "\n");
|
strcat(g_GlslVersionString, "\n");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +168,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
|||||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
bool clip_origin_lower_left = true;
|
||||||
|
#ifdef GL_CLIP_ORIGIN
|
||||||
|
GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
|
||||||
|
if (last_clip_origin == GL_UPPER_LEFT)
|
||||||
|
clip_origin_lower_left = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
@ -175,7 +187,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup viewport, orthographic projection matrix
|
// Setup viewport, orthographic projection matrix
|
||||||
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
||||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
@ -234,7 +246,10 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
|||||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||||
{
|
{
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
|
if (clip_origin_lower_left)
|
||||||
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||||
|
else
|
||||||
|
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||||
@ -306,13 +321,13 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you get an error please report on github. You may try different GL context version or GLSL version.
|
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||||
static bool CheckShader(GLuint handle, const char* desc)
|
static bool CheckShader(GLuint handle, const char* desc)
|
||||||
{
|
{
|
||||||
GLint status = 0, log_length = 0;
|
GLint status = 0, log_length = 0;
|
||||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
if (status == GL_FALSE)
|
if ((GLboolean)status == GL_FALSE)
|
||||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
||||||
if (log_length > 0)
|
if (log_length > 0)
|
||||||
{
|
{
|
||||||
@ -321,17 +336,17 @@ static bool CheckShader(GLuint handle, const char* desc)
|
|||||||
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
fprintf(stderr, "%s\n", buf.begin());
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
}
|
}
|
||||||
return status == GL_TRUE;
|
return (GLboolean)status == GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you get an error please report on github. You may try different GL context version or GLSL version.
|
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||||
static bool CheckProgram(GLuint handle, const char* desc)
|
static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
{
|
{
|
||||||
GLint status = 0, log_length = 0;
|
GLint status = 0, log_length = 0;
|
||||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
if (status == GL_FALSE)
|
if ((GLboolean)status == GL_FALSE)
|
||||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s!\n", desc);
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
||||||
if (log_length > 0)
|
if (log_length > 0)
|
||||||
{
|
{
|
||||||
ImVector<char> buf;
|
ImVector<char> buf;
|
||||||
@ -339,7 +354,7 @@ static bool CheckProgram(GLuint handle, const char* desc)
|
|||||||
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
fprintf(stderr, "%s\n", buf.begin());
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
}
|
}
|
||||||
return status == GL_TRUE;
|
return (GLboolean)status == GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// ImGui Renderer for: OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
|
// dear imgui: Renderer for OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
|
||||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||||
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
||||||
|
|
||||||
@ -19,6 +19,8 @@
|
|||||||
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||||
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
// Set default OpenGL loader to be gl3w
|
// Set default OpenGL loader to be gl3w
|
||||||
#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
||||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
||||||
|
Loading…
Reference in New Issue
Block a user