1
0
mirror of https://github.com/wolfpld/tracy synced 2025-04-30 04:43:53 +00:00

Update ImGui to 1.89.3 + docking.

This commit is contained in:
Bartosz Taudul 2023-02-14 17:57:14 +01:00
parent 122f99c042
commit fad09a452a
No known key found for this signature in database
GPG Key ID: B7FE2008B7575DF3
13 changed files with 818 additions and 483 deletions

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (main code and documentation) // (main code and documentation)
// Help: // Help:
@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq // - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui // - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases // - Releases & changelog https://github.com/ocornut/imgui/releases
// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!) // - Gallery https://github.com/ocornut/imgui/issues/5886 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues // - Issues & support https://github.com/ocornut/imgui/issues
@ -388,12 +388,13 @@ CODE
You can read releases logs https://github.com/ocornut/imgui/releases for more details. You can read releases logs https://github.com/ocornut/imgui/releases for more details.
(Docking/Viewport Branch) (Docking/Viewport Branch)
- 2022/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that: - 2023/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
- reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore. - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos) you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
- likewise io.MousePos and GetMousePos() will use OS coordinates. - likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3.
- 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79. - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79.
- 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details. - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
- 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete). - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete).
@ -1142,6 +1143,9 @@ ImGuiStyle::ImGuiStyle()
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText()
SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
@ -1179,6 +1183,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
TabRounding = ImFloor(TabRounding * scale_factor); TabRounding = ImFloor(TabRounding * scale_factor);
TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor);
DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
@ -1324,7 +1329,6 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{ {
unsigned int c = 0; unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
if (c != 0)
AddInputCharacter(c); AddInputCharacter(c);
} }
} }
@ -1504,7 +1508,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
// Queue a mouse wheel event (most mouse/API will only have a Y component) // Queue a mouse wheel event (some mouse/API may only have a Y component)
void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -1863,19 +1867,37 @@ void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end,
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
{
const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
*out_buf = buf;
if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
}
else
{
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data; *out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
}
va_end(args); va_end(args);
} }
void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
{
const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
*out_buf = buf;
if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
}
else
{
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data; *out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
} }
}
// CRC32 needs a 1KB lookup table (not cache friendly) // CRC32 needs a 1KB lookup table (not cache friendly)
// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
@ -1903,7 +1925,7 @@ static const ImU32 GCrc32LookupTable[256] =
// Known size hash // Known size hash
// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. // It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed) ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
{ {
ImU32 crc = ~seed; ImU32 crc = ~seed;
const unsigned char* data = (const unsigned char*)data_p; const unsigned char* data = (const unsigned char*)data_p;
@ -1919,7 +1941,7 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed)
// - If we reach ### in the string we discard the hash so far and reset to the seed. // - If we reach ### in the string we discard the hash so far and reset to the seed.
// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed) ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
{ {
seed = ~seed; seed = ~seed;
ImU32 crc = seed; ImU32 crc = seed;
@ -1961,7 +1983,7 @@ ImFileHandle ImFileOpen(const char* filename, const char* mode)
// Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
ImVector<ImWchar> buf; ImVector<wchar_t> buf;
buf.resize(filename_wsize + mode_wsize); buf.resize(filename_wsize + mode_wsize);
::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
@ -2024,6 +2046,8 @@ void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_f
// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
IM_MSVC_RUNTIME_CHECKS_OFF
// Convert UTF-8 to 32-bit character, process single character input. // Convert UTF-8 to 32-bit character, process single character input.
// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). // A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).
// We handle UTF-8 decoding error by skipping forward. // We handle UTF-8 decoding error by skipping forward.
@ -2035,7 +2059,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
static const int shiftc[] = { 0, 18, 12, 6, 0 }; static const int shiftc[] = { 0, 18, 12, 6, 0 };
static const int shifte[] = { 0, 6, 4, 2, 0 }; static const int shifte[] = { 0, 6, 4, 2, 0 };
int len = lengths[*(const unsigned char*)in_text >> 3]; int len = lengths[*(const unsigned char*)in_text >> 3];
int wanted = len + !len; int wanted = len + (len ? 0 : 1);
if (in_text_end == NULL) if (in_text_end == NULL)
in_text_end = in_text + wanted; // Max length, nulls will be taken into account. in_text_end = in_text + wanted; // Max length, nulls will be taken into account.
@ -2087,8 +2111,6 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha
{ {
unsigned int c; unsigned int c;
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
*buf_out++ = (ImWchar)c; *buf_out++ = (ImWchar)c;
} }
*buf_out = 0; *buf_out = 0;
@ -2104,8 +2126,6 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
{ {
unsigned int c; unsigned int c;
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
char_count++; char_count++;
} }
return char_count; return char_count;
@ -2199,6 +2219,7 @@ int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_e
} }
return bytes_count; return bytes_count;
} }
IM_MSVC_RUNTIME_CHECKS_RESTORE
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] MISC HELPERS/UTILITIES (Color functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions)
@ -3069,6 +3090,9 @@ static const ImGuiStyleVarInfo GStyleVarInfo[] =
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
}; };
static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
@ -3300,7 +3324,6 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
LogRenderedText(&pos_min, text, text_display_end); LogRenderedText(&pos_min, text, text_display_end);
} }
// Another overly complex function until we reorganize everything into a nice all-in-one helper. // Another overly complex function until we reorganize everything into a nice all-in-one helper.
// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
@ -3324,30 +3347,12 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
const ImFont* font = draw_list->_Data->Font; const ImFont* font = draw_list->_Data->Font;
const float font_size = draw_list->_Data->FontSize; const float font_size = draw_list->_Data->FontSize;
const float font_scale = font_size / font->FontSize;
const char* text_end_ellipsis = NULL; const char* text_end_ellipsis = NULL;
const float ellipsis_width = font->EllipsisWidth * font_scale;
ImWchar ellipsis_char = font->EllipsisChar;
int ellipsis_char_count = 1;
if (ellipsis_char == (ImWchar)-1)
{
ellipsis_char = font->DotChar;
ellipsis_char_count = 3;
}
const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side
float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis
if (ellipsis_char_count > 1)
{
// Full ellipsis size without free spacing after it.
const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
}
// We can now claim the space between pos_max.x and ellipsis_max.x // We can now claim the space between pos_max.x and ellipsis_max.x
const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
{ {
@ -3364,13 +3369,10 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
// Render text, render ellipsis // Render text, render ellipsis
RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
float ellipsis_x = pos_min.x + text_size_clipped_x; ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));
if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x)
for (int i = 0; i < ellipsis_char_count; i++) for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale)
{ font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar);
font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
ellipsis_x += ellipsis_glyph_width;
}
} }
else else
{ {
@ -3711,7 +3713,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst
ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
AutoFitFramesX = AutoFitFramesY = -1; AutoFitFramesX = AutoFitFramesY = -1;
AutoPosLastDirection = ImGuiDir_None; AutoPosLastDirection = ImGuiDir_None;
SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = 0;
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
LastFrameActive = -1; LastFrameActive = -1;
LastFrameJustFocused = -1; LastFrameJustFocused = -1;
@ -5063,10 +5065,12 @@ void ImGui::EndFrame()
ErrorCheckEndFrameSanityChecks(); ErrorCheckEndFrameSanityChecks();
// Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
if (g.IO.SetPlatformImeDataFn && memcmp(&g.PlatformImeData, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) ImGuiPlatformImeData* ime_data = &g.PlatformImeData;
if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
{ {
ImGuiViewport* viewport = FindViewportByID(g.PlatformImeViewport); ImGuiViewport* viewport = FindViewportByID(g.PlatformImeViewport);
g.IO.SetPlatformImeDataFn(viewport ? viewport : GetMainViewport(), &g.PlatformImeData); IMGUI_DEBUG_LOG_IO("Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
g.IO.SetPlatformImeDataFn(viewport ? viewport : GetMainViewport(), ime_data);
} }
// Hide implicit/fallback "Debug" window if it hasn't been used // Hide implicit/fallback "Debug" window if it hasn't been used
@ -5632,33 +5636,23 @@ static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created,
window->IsExplicitChild = new_is_explicit_child; window->IsExplicitChild = new_is_explicit_child;
} }
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
{ {
ImGuiContext& g = *GImGui; // Initial window state with e.g. default/arbitrary window position
//IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
// Create window the first time
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
window->Flags = flags;
g.WindowsById.SetVoidPtr(window->ID, window);
// Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
window->Pos = main_viewport->Pos + ImVec2(60, 60); window->Pos = main_viewport->Pos + ImVec2(60, 60);
window->ViewportPos = main_viewport->Pos; window->ViewportPos = main_viewport->Pos;
window->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = window->SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
// User can disable loading and saving of settings. Tooltip and child windows also don't store settings. if (settings != NULL)
if (!(flags & ImGuiWindowFlags_NoSavedSettings))
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
{ {
// Retrieve settings from .ini file
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
ApplyWindowSettings(window, settings); ApplyWindowSettings(window, settings);
} }
window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
{ {
window->AutoFitFramesX = window->AutoFitFramesY = 2; window->AutoFitFramesX = window->AutoFitFramesY = 2;
window->AutoFitOnlyGrows = false; window->AutoFitOnlyGrows = false;
@ -5671,6 +5665,23 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
window->AutoFitFramesY = 2; window->AutoFitFramesY = 2;
window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
} }
}
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
{
// Create window the first time
//IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
window->Flags = flags;
g.WindowsById.SetVoidPtr(window->ID, window);
ImGuiWindowSettings* settings = NULL;
if (!(flags & ImGuiWindowFlags_NoSavedSettings))
if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0)
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
InitOrLoadWindowSettings(window, settings);
if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
g.Windows.push_front(window); // Quite slow but rare and only once g.Windows.push_front(window); // Quite slow but rare and only once
@ -6197,12 +6208,15 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
{ {
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
{ {
const ImU32 col = resize_grip_col[resize_grip_n];
if ((col & IM_COL32_A_MASK) == 0)
continue;
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); window->DrawList->PathFillConvex(col);
} }
} }
@ -8120,6 +8134,15 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
return id; return id;
} }
ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed)
{
ImGuiID id = ImHashData(&n, sizeof(n), seed);
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
return id;
}
void ImGui::PopID() void ImGui::PopID()
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiWindow* window = GImGui->CurrentWindow;
@ -9099,7 +9122,8 @@ void ImGui::UpdateMouseWheel()
// Mouse wheel scrolling // Mouse wheel scrolling
// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
// (we avoid doing it on OSX as it the OS input layer handles this already) // - We avoid doing it on OSX as it the OS input layer handles this already.
// - However this means when running on OSX over Emcripten, Shift+WheelY will incur two swappings (1 in OS, 1 here), cancelling the feature.
const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors; const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
if (swap_axis) if (swap_axis)
{ {
@ -9486,6 +9510,13 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
// #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct! // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct!
if (true) IM_ASSERT(1); else IM_ASSERT(0); if (true) IM_ASSERT(1); else IM_ASSERT(0);
// Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644)
// Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it.
#ifdef __EMSCRIPTEN__
if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0)
g.IO.DeltaTime = 0.00001f;
#endif
// Check user data // Check user data
// (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
IM_ASSERT(g.Initialized); IM_ASSERT(g.Initialized);
@ -10621,7 +10652,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
const int current_stack_size = g.BeginPopupStack.Size; const int current_stack_size = g.BeginPopupStack.Size;
if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)
if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId)) if (IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId))
return; return;
ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
@ -13099,15 +13130,17 @@ void ImGui::LogButtons()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// - UpdateSettings() [Internal] // - UpdateSettings() [Internal]
// - MarkIniSettingsDirty() [Internal] // - MarkIniSettingsDirty() [Internal]
// - CreateNewWindowSettings() [Internal]
// - FindWindowSettings() [Internal]
// - FindOrCreateWindowSettings() [Internal]
// - FindSettingsHandler() [Internal] // - FindSettingsHandler() [Internal]
// - ClearIniSettings() [Internal] // - ClearIniSettings() [Internal]
// - LoadIniSettingsFromDisk() // - LoadIniSettingsFromDisk()
// - LoadIniSettingsFromMemory() // - LoadIniSettingsFromMemory()
// - SaveIniSettingsToDisk() // - SaveIniSettingsToDisk()
// - SaveIniSettingsToMemory() // - SaveIniSettingsToMemory()
//-----------------------------------------------------------------------------
// - CreateNewWindowSettings() [Internal]
// - FindWindowSettingsByID() [Internal]
// - FindWindowSettingsByWindow() [Internal]
// - ClearWindowSettings() [Internal]
// - WindowSettingsHandler_***() [Internal] // - WindowSettingsHandler_***() [Internal]
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -13154,44 +13187,6 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
g.SettingsDirtyTimer = g.IO.IniSavingRate; g.SettingsDirtyTimer = g.IO.IniSavingRate;
} }
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
{
ImGuiContext& g = *GImGui;
#if !IMGUI_DEBUG_INI_SETTINGS
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
if (const char* p = strstr(name, "###"))
name = p;
#endif
const size_t name_len = strlen(name);
// Allocate chunk
const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
settings->ID = ImHashStr(name, name_len);
memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
return settings;
}
ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
{
ImGuiContext& g = *GImGui;
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (settings->ID == id)
return settings;
return NULL;
}
ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
{
if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
return settings;
return CreateNewWindowSettings(name);
}
void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -13216,6 +13211,7 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
return NULL; return NULL;
} }
// Clear all settings (windows, tables, docking etc.)
void ImGui::ClearIniSettings() void ImGui::ClearIniSettings()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -13340,6 +13336,65 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
return g.SettingsIniData.c_str(); return g.SettingsIniData.c_str();
} }
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
{
ImGuiContext& g = *GImGui;
#if !IMGUI_DEBUG_INI_SETTINGS
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
if (const char* p = strstr(name, "###"))
name = p;
#endif
const size_t name_len = strlen(name);
// Allocate chunk
const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
settings->ID = ImHashStr(name, name_len);
memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
return settings;
}
// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names.
// This is called once per window .ini entry + once per newly instantiated window.
ImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (settings->ID == id)
return settings;
return NULL;
}
// This is faster if you are holding on a Window already as we don't need to perform a search.
ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
if (window->SettingsOffset != -1)
return g.SettingsWindows.ptr_from_offset(window->SettingsOffset);
return FindWindowSettingsByID(window->ID);
}
// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more.
void ImGui::ClearWindowSettings(const char* name)
{
//IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = FindWindowByName(name);
if (window != NULL)
{
window->Flags |= ImGuiWindowFlags_NoSavedSettings;
InitOrLoadWindowSettings(window, NULL);
if (window->DockId != 0)
DockContextProcessUndockWindow(&g, window, true);
}
if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name)))
settings->WantDelete = true;
}
static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
@ -13350,9 +13405,12 @@ static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandl
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{ {
ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); ImGuiID id = ImHashStr(name);
ImGuiID id = settings->ID; ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id);
if (settings)
*settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
else
settings = ImGui::CreateNewWindowSettings(name);
settings->ID = id; settings->ID = id;
settings->WantApply = true; settings->WantApply = true;
return (void*)settings; return (void*)settings;
@ -13398,7 +13456,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (window->Flags & ImGuiWindowFlags_NoSavedSettings) if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
continue; continue;
ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window);
if (!settings) if (!settings)
{ {
settings = ImGui::CreateNewWindowSettings(window->Name); settings = ImGui::CreateNewWindowSettings(window->Name);
@ -13414,12 +13472,15 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
settings->ClassId = window->WindowClass.ClassId; settings->ClassId = window->WindowClass.ClassId;
settings->DockOrder = window->DockOrder; settings->DockOrder = window->DockOrder;
settings->Collapsed = window->Collapsed; settings->Collapsed = window->Collapsed;
settings->WantDelete = false;
} }
// Write to text buffer // Write to text buffer
buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{ {
if (settings->WantDelete)
continue;
const char* settings_name = settings->GetName(); const char* settings_name = settings->GetName();
buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID) if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
@ -14565,8 +14626,6 @@ namespace ImGui
static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node); static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node);
static void DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node); static void DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node);
static void DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req); static void DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req);
static void DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref = true);
static void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
static void DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx); static void DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx);
static ImGuiDockNode* DockContextBindNodeToWindow(ImGuiContext* ctx, ImGuiWindow* window); static ImGuiDockNode* DockContextBindNodeToWindow(ImGuiContext* ctx, ImGuiWindow* window);
static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count); static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count);
@ -14891,7 +14950,7 @@ static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx)
{ {
ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n]; ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n];
if (settings->ParentWindowId != 0) if (settings->ParentWindowId != 0)
if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->ParentWindowId)) if (ImGuiWindowSettings* window_settings = FindWindowSettingsByID(settings->ParentWindowId))
if (window_settings->DockId) if (window_settings->DockId)
if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(window_settings->DockId)) if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(window_settings->DockId))
data->CountChildNodes++; data->CountChildNodes++;
@ -15335,7 +15394,7 @@ int ImGui::DockNodeGetTabOrder(ImGuiWindow* window)
if (tab_bar == NULL) if (tab_bar == NULL)
return -1; return -1;
ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, window->TabId); ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, window->TabId);
return tab ? tab_bar->GetTabOrder(tab) : -1; return tab ? TabBarGetTabOrder(tab_bar, tab) : -1;
} }
static void DockNodeHideWindowDuringHostWindowCreation(ImGuiWindow* window) static void DockNodeHideWindowDuringHostWindowCreation(ImGuiWindow* window)
@ -16087,7 +16146,7 @@ static ImGuiID ImGui::DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar*
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
if (tab->Flags & ImGuiTabItemFlags_Button) if (tab->Flags & ImGuiTabItemFlags_Button)
continue; continue;
if (Selectable(tab_bar->GetTabName(tab), tab->ID == tab_bar->SelectedTabId)) if (Selectable(TabBarGetTabName(tab_bar, tab), tab->ID == tab_bar->SelectedTabId))
ret_tab_id = tab->ID; ret_tab_id = tab->ID;
SameLine(); SameLine();
Text(" "); Text(" ");
@ -17389,7 +17448,7 @@ void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id)
else else
{ {
// Apply to settings // Apply to settings
ImGuiWindowSettings* settings = FindWindowSettings(window_id); ImGuiWindowSettings* settings = FindWindowSettingsByID(window_id);
if (settings == NULL) if (settings == NULL)
settings = CreateNewWindowSettings(window_name); settings = CreateNewWindowSettings(window_name);
settings->DockId = node_id; settings->DockId = node_id;
@ -17670,8 +17729,11 @@ void ImGui::DockBuilderCopyWindowSettings(const char* src_name, const char* dst_
dst_window->SizeFull = src_window->SizeFull; dst_window->SizeFull = src_window->SizeFull;
dst_window->Collapsed = src_window->Collapsed; dst_window->Collapsed = src_window->Collapsed;
} }
else if (ImGuiWindowSettings* dst_settings = FindOrCreateWindowSettings(dst_name)) else
{ {
ImGuiWindowSettings* dst_settings = FindWindowSettingsByID(ImHashStr(dst_name));
if (!dst_settings)
dst_settings = CreateNewWindowSettings(dst_name);
ImVec2ih window_pos_2ih = ImVec2ih(src_window->Pos); ImVec2ih window_pos_2ih = ImVec2ih(src_window->Pos);
if (src_window->ViewportId != 0 && src_window->ViewportId != IMGUI_VIEWPORT_DEFAULT_ID) if (src_window->ViewportId != 0 && src_window->ViewportId != IMGUI_VIEWPORT_DEFAULT_ID)
{ {
@ -17717,7 +17779,7 @@ void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_docks
ImGuiID src_dock_id = 0; ImGuiID src_dock_id = 0;
if (ImGuiWindow* src_window = FindWindowByID(src_window_id)) if (ImGuiWindow* src_window = FindWindowByID(src_window_id))
src_dock_id = src_window->DockId; src_dock_id = src_window->DockId;
else if (ImGuiWindowSettings* src_window_settings = FindWindowSettings(src_window_id)) else if (ImGuiWindowSettings* src_window_settings = FindWindowSettingsByID(src_window_id))
src_dock_id = src_window_settings->DockId; src_dock_id = src_window_settings->DockId;
ImGuiID dst_dock_id = 0; ImGuiID dst_dock_id = 0;
for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2) for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2)
@ -18663,10 +18725,13 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
DebugNodeFont(font); DebugNodeFont(font);
PopID(); PopID();
} }
if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
{ {
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); ImGuiContext& g = *GImGui;
ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons
ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border);
Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
TreePop(); TreePop();
} }
@ -19054,7 +19119,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{ {
if (ImGuiWindow* window = FindWindowByID(settings->SelectedTabId)) if (ImGuiWindow* window = FindWindowByID(settings->SelectedTabId))
selected_tab_name = window->Name; selected_tab_name = window->Name;
else if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->SelectedTabId)) else if (ImGuiWindowSettings* window_settings = FindWindowSettingsByID(settings->SelectedTabId))
selected_tab_name = window_settings->GetName(); selected_tab_name = window_settings->GetName();
} }
BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeId, settings->SelectedTabId, selected_tab_name ? selected_tab_name : settings->SelectedTabId ? "N/A" : ""); BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeId, settings->SelectedTabId, selected_tab_name ? selected_tab_name : settings->SelectedTabId ? "N/A" : "");
@ -19629,8 +19694,7 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)
{ {
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
p += ImFormatString(p, buf_end - p, "%s'%s'", p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab));
tab_n > 0 ? ", " : "", (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???");
} }
p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
@ -19647,12 +19711,12 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
{ {
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{ {
const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
PushID(tab); PushID(tab);
if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2); if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine(); if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f", Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f",
tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???", tab->Offset, tab->Width, tab->ContentWidth); tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth);
PopID(); PopID();
} }
TreePop(); TreePop();
@ -19757,8 +19821,12 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings)
{ {
if (settings->WantDelete)
BeginDisabled();
Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
if (settings->WantDelete)
EndDisabled();
} }
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label) void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label)

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (headers) // (headers)
// Help: // Help:
@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq // - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui // - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases // - Releases & changelog https://github.com/ocornut/imgui/releases
// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!) // - Gallery https://github.com/ocornut/imgui/issues/5886 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues // - Issues & support https://github.com/ocornut/imgui/issues
@ -22,8 +22,8 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
#define IMGUI_VERSION "1.89.2" #define IMGUI_VERSION "1.89.3"
#define IMGUI_VERSION_NUM 18920 #define IMGUI_VERSION_NUM 18930
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch
@ -502,6 +502,7 @@ namespace ImGui
IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2);
IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text()
IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1);
IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line
// Widgets: Main // Widgets: Main
// - Most widgets return true when the value has been changed or when pressed/selected // - Most widgets return true when the value has been changed or when pressed/selected
@ -1683,6 +1684,9 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabRounding, // float TabRounding
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize
ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding
ImGuiStyleVar_COUNT ImGuiStyleVar_COUNT
}; };
@ -1937,6 +1941,9 @@ struct ImGuiStyle
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
float SeparatorTextBorderSize; // Thickkness of border in SeparatorText()
ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later.
@ -2055,7 +2062,7 @@ struct ImGuiIO
IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend.
IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered)
IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change
IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left.
IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this (for multi-viewport support). IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this (for multi-viewport support).
IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window)
IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input
@ -2106,8 +2113,8 @@ struct ImGuiIO
// (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)
ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)
bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll.
float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows).
bool KeyCtrl; // Keyboard modifier down: Control bool KeyCtrl; // Keyboard modifier down: Control
bool KeyShift; // Keyboard modifier down: Shift bool KeyShift; // Keyboard modifier down: Shift
@ -2769,7 +2776,7 @@ struct ImFontConfig
bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input.
const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
@ -2971,8 +2978,10 @@ struct ImFont
const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData
short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found.
ImWchar EllipsisChar; // 2 // out // = '...' // Character used for ellipsis rendering. ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering.
ImWchar DotChar; // 2 // out // = '.' // Character used for ellipsis rendering (if a single '...' character isn't found) short EllipsisCharCount; // 1 // out // 1 or 3
float EllipsisWidth; // 4 // out // Width
float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0
bool DirtyLookupTables; // 1 // out // bool DirtyLookupTables; // 1 // out //
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (demo code) // (demo code)
// Help: // Help:
@ -443,6 +443,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::TreeNode("Configuration##2")) if (ImGui::TreeNode("Configuration##2"))
{ {
ImGui::SeparatorText("General");
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
ImGui::SameLine(); HelpMarker("Enable keyboard controls."); ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
@ -502,6 +503,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::SeparatorText("Widgets");
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
@ -511,11 +516,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::Text("Also see Style->Rendering for rendering options."); ImGui::Text("Also see Style->Rendering for rendering options.");
ImGui::TreePop(); ImGui::TreePop();
ImGui::Separator(); ImGui::Spacing();
} }
IMGUI_DEMO_MARKER("Configuration/Backend Flags"); IMGUI_DEMO_MARKER("Configuration/Backend Flags");
@ -536,7 +540,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset);
ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &backend_flags, ImGuiBackendFlags_RendererHasViewports); ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &backend_flags, ImGuiBackendFlags_RendererHasViewports);
ImGui::TreePop(); ImGui::TreePop();
ImGui::Separator(); ImGui::Spacing();
} }
IMGUI_DEMO_MARKER("Configuration/Style"); IMGUI_DEMO_MARKER("Configuration/Style");
@ -545,7 +549,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
ImGui::ShowStyleEditor(); ImGui::ShowStyleEditor();
ImGui::TreePop(); ImGui::TreePop();
ImGui::Separator(); ImGui::Spacing();
} }
IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
@ -614,6 +618,8 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Basic"); IMGUI_DEMO_MARKER("Widgets/Basic");
if (ImGui::TreeNode("Basic")) if (ImGui::TreeNode("Basic"))
{ {
ImGui::SeparatorText("General");
IMGUI_DEMO_MARKER("Widgets/Basic/Button"); IMGUI_DEMO_MARKER("Widgets/Basic/Button");
static int clicked = 0; static int clicked = 0;
if (ImGui::Button("Button")) if (ImGui::Button("Button"))
@ -668,19 +674,42 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("%d", counter); ImGui::Text("%d", counter);
ImGui::Separator(); {
// Tooltips
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
//ImGui::AlignTextToFramePadding();
ImGui::Text("Tooltips:");
ImGui::SameLine();
ImGui::SmallButton("Button");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::SmallButton("Fancy");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::EndTooltip();
}
ImGui::SameLine();
ImGui::SmallButton("Delayed");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // With a delay
ImGui::SetTooltip("I am a tooltip with a delay.");
ImGui::SameLine();
HelpMarker(
"Tooltip are created by using the IsItemHovered() function over any kind of item.");
}
ImGui::LabelText("label", "Value"); ImGui::LabelText("label", "Value");
{ ImGui::SeparatorText("Inputs");
// Using the _simplified_ one-liner Combo() api here
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
static int item_current = 0;
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
}
{ {
// To wire InputText() with std::string or any other custom string type, // To wire InputText() with std::string or any other custom string type,
@ -724,6 +753,8 @@ static void ShowDemoWindowWidgets()
ImGui::InputFloat3("input float3", vec4a); ImGui::InputFloat3("input float3", vec4a);
} }
ImGui::SeparatorText("Drags");
{ {
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
static int i1 = 50, i2 = 42; static int i1 = 50, i2 = 42;
@ -740,6 +771,8 @@ static void ShowDemoWindowWidgets()
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
} }
ImGui::SeparatorText("Sliders");
{ {
IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
static int i1 = 0; static int i1 = 0;
@ -766,6 +799,8 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
} }
ImGui::SeparatorText("Selectors/Pickers");
{ {
IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
static float col1[3] = { 1.0f, 0.0f, 0.2f }; static float col1[3] = { 1.0f, 0.0f, 0.2f };
@ -780,6 +815,17 @@ static void ShowDemoWindowWidgets()
ImGui::ColorEdit4("color 2", col2); ImGui::ColorEdit4("color 2", col2);
} }
{
// Using the _simplified_ one-liner Combo() api here
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
static int item_current = 0;
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
}
{ {
// Using the _simplified_ one-liner ListBox() api here // Using the _simplified_ one-liner ListBox() api here
// See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
@ -791,40 +837,6 @@ static void ShowDemoWindowWidgets()
"Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
} }
{
// Tooltips
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
ImGui::AlignTextToFramePadding();
ImGui::Text("Tooltips:");
ImGui::SameLine();
ImGui::Button("Button");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::Button("Fancy");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::EndTooltip();
}
ImGui::SameLine();
ImGui::Button("Delayed");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // Delay best used on items that highlight on hover, so this not a great example!
ImGui::SetTooltip("I am a tooltip with a delay.");
ImGui::SameLine();
HelpMarker(
"Tooltip are created by using the IsItemHovered() function over any kind of item.");
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -1084,12 +1096,14 @@ static void ShowDemoWindowWidgets()
float my_tex_w = (float)io.Fonts->TexWidth; float my_tex_w = (float)io.Fonts->TexWidth;
float my_tex_h = (float)io.Fonts->TexHeight; float my_tex_h = (float)io.Fonts->TexHeight;
{ {
static bool use_text_color_for_tint = false;
ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -1747,7 +1761,7 @@ static void ShowDemoWindowWidgets()
} }
// Use functions to generate output // Use functions to generate output
// FIXME: This is rather awkward because current plot API only pass in indices. // FIXME: This is actually VERY awkward because current plot API only pass in indices.
// We probably want an API passing floats and user provide sample rate/count. // We probably want an API passing floats and user provide sample rate/count.
struct Funcs struct Funcs
{ {
@ -1755,7 +1769,7 @@ static void ShowDemoWindowWidgets()
static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
}; };
static int func_type = 0, display_count = 70; static int func_type = 0, display_count = 70;
ImGui::Separator(); ImGui::SeparatorText("Functions");
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::Combo("func", &func_type, "Sin\0Saw\0");
ImGui::SameLine(); ImGui::SameLine();
@ -1798,6 +1812,7 @@ static void ShowDemoWindowWidgets()
static bool drag_and_drop = true; static bool drag_and_drop = true;
static bool options_menu = true; static bool options_menu = true;
static bool hdr = false; static bool hdr = false;
ImGui::SeparatorText("Options");
ImGui::Checkbox("With Alpha Preview", &alpha_preview); ImGui::Checkbox("With Alpha Preview", &alpha_preview);
ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
ImGui::Checkbox("With Drag and Drop", &drag_and_drop); ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
@ -1806,6 +1821,7 @@ static void ShowDemoWindowWidgets()
ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
ImGui::SeparatorText("Inline color editor");
ImGui::Text("Color widget:"); ImGui::Text("Color widget:");
ImGui::SameLine(); HelpMarker( ImGui::SameLine(); HelpMarker(
"Click on the color square to open a color picker.\n" "Click on the color square to open a color picker.\n"
@ -1903,7 +1919,7 @@ static void ShowDemoWindowWidgets()
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
ImGui::Text("Color picker:"); ImGui::SeparatorText("Color picker");
static bool alpha = true; static bool alpha = true;
static bool alpha_bar = true; static bool alpha_bar = true;
static bool side_preview = true; static bool side_preview = true;
@ -2074,7 +2090,7 @@ static void ShowDemoWindowWidgets()
const float drag_speed = 0.2f; const float drag_speed = 0.2f;
static bool drag_clamp = false; static bool drag_clamp = false;
IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
ImGui::Text("Drags:"); ImGui::SeparatorText("Drags");
ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
ImGui::SameLine(); HelpMarker( ImGui::SameLine(); HelpMarker(
"As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
@ -2094,7 +2110,7 @@ static void ShowDemoWindowWidgets()
ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
ImGui::Text("Sliders"); ImGui::SeparatorText("Sliders");
ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
@ -2119,7 +2135,7 @@ static void ShowDemoWindowWidgets()
ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
ImGui::Text("Sliders (reverse)"); ImGui::SeparatorText("Sliders (reverse)");
ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
@ -2129,7 +2145,7 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
static bool inputs_step = true; static bool inputs_step = true;
ImGui::Text("Inputs"); ImGui::SeparatorText("Inputs");
ImGui::Checkbox("Show step buttons", &inputs_step); ImGui::Checkbox("Show step buttons", &inputs_step);
ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
@ -2153,22 +2169,23 @@ static void ShowDemoWindowWidgets()
static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
static int vec4i[4] = { 1, 5, 100, 255 }; static int vec4i[4] = { 1, 5, 100, 255 };
ImGui::SeparatorText("2-wide");
ImGui::InputFloat2("input float2", vec4f); ImGui::InputFloat2("input float2", vec4f);
ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
ImGui::InputInt2("input int2", vec4i); ImGui::InputInt2("input int2", vec4i);
ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
ImGui::SliderInt2("slider int2", vec4i, 0, 255); ImGui::SliderInt2("slider int2", vec4i, 0, 255);
ImGui::Spacing();
ImGui::SeparatorText("3-wide");
ImGui::InputFloat3("input float3", vec4f); ImGui::InputFloat3("input float3", vec4f);
ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
ImGui::InputInt3("input int3", vec4i); ImGui::InputInt3("input int3", vec4i);
ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
ImGui::SliderInt3("slider int3", vec4i, 0, 255); ImGui::SliderInt3("slider int3", vec4i, 0, 255);
ImGui::Spacing();
ImGui::SeparatorText("4-wide");
ImGui::InputFloat4("input float4", vec4f); ImGui::InputFloat4("input float4", vec4f);
ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
@ -2600,6 +2617,8 @@ static void ShowDemoWindowLayout()
IMGUI_DEMO_MARKER("Layout/Child windows"); IMGUI_DEMO_MARKER("Layout/Child windows");
if (ImGui::TreeNode("Child windows")) if (ImGui::TreeNode("Child windows"))
{ {
ImGui::SeparatorText("Child windows");
HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
static bool disable_mouse_wheel = false; static bool disable_mouse_wheel = false;
static bool disable_menu = false; static bool disable_menu = false;
@ -2652,7 +2671,7 @@ static void ShowDemoWindowLayout()
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
ImGui::Separator(); ImGui::SeparatorText("Misc/Advanced");
// Demonstrate a few extra things // Demonstrate a few extra things
// - Changing ImGuiCol_ChildBg (which is transparent black in default styles) // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
@ -3416,8 +3435,7 @@ static void ShowDemoWindowPopups()
ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
if (ImGui::BeginPopup("my_select_popup")) if (ImGui::BeginPopup("my_select_popup"))
{ {
ImGui::Text("Aquarium"); ImGui::SeparatorText("Aquarium");
ImGui::Separator();
for (int i = 0; i < IM_ARRAYSIZE(names); i++) for (int i = 0; i < IM_ARRAYSIZE(names); i++)
if (ImGui::Selectable(names[i])) if (ImGui::Selectable(names[i]))
selected_fish = i; selected_fish = i;
@ -3594,7 +3612,7 @@ static void ShowDemoWindowPopups()
if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{ {
ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
ImGui::Separator(); ImGui::Separator();
//static int unused_i = 0; //static int unused_i = 0;
@ -6067,6 +6085,9 @@ void ImGui::ShowAboutWindow(bool* p_open)
#ifdef __clang_version__ #ifdef __clang_version__
ImGui::Text("define: __clang_version__=%s", __clang_version__); ImGui::Text("define: __clang_version__=%s", __clang_version__);
#endif #endif
#ifdef __EMSCRIPTEN__
ImGui::Text("define: __EMSCRIPTEN__");
#endif
#ifdef IMGUI_HAS_VIEWPORT #ifdef IMGUI_HAS_VIEWPORT
ImGui::Text("define: IMGUI_HAS_VIEWPORT"); ImGui::Text("define: IMGUI_HAS_VIEWPORT");
#endif #endif
@ -6236,7 +6257,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{ {
if (ImGui::BeginTabItem("Sizes")) if (ImGui::BeginTabItem("Sizes"))
{ {
ImGui::Text("Main"); ImGui::SeparatorText("Main");
ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
@ -6246,22 +6267,24 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
ImGui::Text("Borders");
ImGui::SeparatorText("Borders");
ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::Text("Rounding");
ImGui::SeparatorText("Rounding");
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment");
ImGui::SeparatorText("Widgets");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
int window_menu_button_position = style.WindowMenuButtonPosition + 1; int window_menu_button_position = style.WindowMenuButtonPosition + 1;
if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
@ -6271,9 +6294,13 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
ImGui::Text("Safe Area Padding"); ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%0.f");
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
ImGui::SeparatorText("Misc");
ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
@ -6583,6 +6610,7 @@ static void ShowExampleMenuFile()
IM_ASSERT(0); IM_ASSERT(0);
} }
if (ImGui::MenuItem("Checked", NULL, true)) {} if (ImGui::MenuItem("Checked", NULL, true)) {}
ImGui::Separator();
if (ImGui::MenuItem("Quit", "Alt+F4")) {} if (ImGui::MenuItem("Quit", "Alt+F4")) {}
} }

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (drawing and font code) // (drawing and font code)
/* /*
@ -714,7 +714,7 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. // 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, ImDrawFlags flags, float thickness) void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
{ {
if (points_count < 2) if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
return; return;
const bool closed = (flags & ImDrawFlags_Closed) != 0; const bool closed = (flags & ImDrawFlags_Closed) != 0;
@ -972,7 +972,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
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) if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
return; return;
const ImVec2 uv = _Data->TexUvWhitePixel; const ImVec2 uv = _Data->TexUvWhitePixel;
@ -2390,7 +2390,12 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); 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) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
{
// Check for valid range. This may also help detect *some* dangling pointers, because a common
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
IM_ASSERT(src_range[0] <= src_range[1]);
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
}
dst_tmp.SrcCount++; dst_tmp.SrcCount++;
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
} }
@ -2945,19 +2950,19 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
// 2999 ideograms code points for Japanese // 2999 ideograms code points for Japanese
// - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
// - 863 Jinmeiyo (meaning "for personal name") Kanji code points // - 863 Jinmeiyo (meaning "for personal name") Kanji code points
// - Sourced from the character information database of the Information-technology Promotion Agency, Japan // - Sourced from official information provided by the government agencies of Japan:
// - https://mojikiban.ipa.go.jp/mji/ // - List of Joyo Kanji by the Agency for Cultural Affairs
// - Available under the terms of the Creative Commons Attribution-ShareAlike 2.1 Japan (CC BY-SA 2.1 JP). // - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
// - https://creativecommons.org/licenses/by-sa/2.1/jp/deed.en // - List of Jinmeiyo Kanji by the Ministry of Justice
// - https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode // - http://www.moj.go.jp/MINJI/minji86.html
// - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).
// - https://creativecommons.org/licenses/by/4.0/legalcode
// - You can generate this code by the script at: // - You can generate this code by the script at:
// - https://github.com/vaiorabbit/everyday_use_kanji // - https://github.com/vaiorabbit/everyday_use_kanji
// - References: // - References:
// - List of Joyo Kanji // - List of Joyo Kanji
// - (Official list by the Agency for Cultural Affairs) https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kakuki/14/tosin02/index.html
// - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
// - List of Jinmeiyo Kanji // - List of Jinmeiyo Kanji
// - (Official list by the Ministry of Justice) http://www.moj.go.jp/MINJI/minji86.html
// - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
// - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.
// You can use ImFontGlyphRangesBuilder 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.
@ -3120,7 +3125,8 @@ ImFont::ImFont()
FallbackAdvanceX = 0.0f; FallbackAdvanceX = 0.0f;
FallbackChar = (ImWchar)-1; FallbackChar = (ImWchar)-1;
EllipsisChar = (ImWchar)-1; EllipsisChar = (ImWchar)-1;
DotChar = (ImWchar)-1; EllipsisWidth = EllipsisCharStep = 0.0f;
EllipsisCharCount = 0;
FallbackGlyph = NULL; FallbackGlyph = NULL;
ContainerAtlas = NULL; ContainerAtlas = NULL;
ConfigData = NULL; ConfigData = NULL;
@ -3208,8 +3214,20 @@ void ImFont::BuildLookupTable()
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
if (EllipsisChar == (ImWchar)-1) if (EllipsisChar == (ImWchar)-1)
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
if (DotChar == (ImWchar)-1) const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); if (EllipsisChar != (ImWchar)-1)
{
EllipsisCharCount = 1;
EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1;
}
else if (dot_char != (ImWchar)-1)
{
const ImFontGlyph* glyph = FindGlyph(dot_char);
EllipsisChar = dot_char;
EllipsisCharCount = 3;
EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f;
EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f;
}
// Setup fallback character // Setup fallback character
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
@ -3377,6 +3395,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
bool inside_word = true; bool inside_word = true;
const char* s = text; const char* s = text;
IM_ASSERT(text_end != NULL);
while (s < text_end) while (s < text_end)
{ {
unsigned int c = (unsigned int)*s; unsigned int c = (unsigned int)*s;
@ -3385,8 +3404,6 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
next_s = s + 1; next_s = s + 1;
else else
next_s = s + ImTextCharFromUtf8(&c, s, text_end); next_s = s + ImTextCharFromUtf8(&c, s, text_end);
if (c == 0)
break;
if (c < 32) if (c < 32)
{ {
@ -3492,15 +3509,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
const char* prev_s = s; const char* prev_s = s;
unsigned int c = (unsigned int)*s; unsigned int c = (unsigned int)*s;
if (c < 0x80) if (c < 0x80)
{
s += 1; s += 1;
}
else else
{
s += ImTextCharFromUtf8(&c, s, text_end); s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}
if (c < 32) if (c < 32)
{ {
@ -3575,18 +3586,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
while (y + line_height < clip_rect.y && s < text_end) while (y + line_height < clip_rect.y && s < text_end)
{ {
const char* line_end = (const char*)memchr(s, '\n', text_end - s); const char* line_end = (const char*)memchr(s, '\n', text_end - s);
const char* line_next = line_end ? line_end + 1 : text_end;
if (word_wrap_enabled) if (word_wrap_enabled)
{ {
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
// If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both.
// However it is still better than nothing performing the fast-forward! // However it is still better than nothing performing the fast-forward!
s = CalcWordWrapPositionA(scale, s, line_next, wrap_width); s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width);
s = CalcWordWrapNextLineStartA(s, text_end); s = CalcWordWrapNextLineStartA(s, text_end);
} }
else else
{ {
s = line_next; s = line_end ? line_end + 1 : text_end;
} }
y += line_height; y += line_height;
} }
@ -3613,10 +3623,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
const int idx_count_max = (int)(text_end - s) * 6; const int idx_count_max = (int)(text_end - s) * 6;
const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
draw_list->PrimReserve(idx_count_max, vtx_count_max); draw_list->PrimReserve(idx_count_max, vtx_count_max);
ImDrawVert* vtx_write = draw_list->_VtxWritePtr; ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
ImDrawIdx* idx_write = draw_list->_IdxWritePtr; ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; unsigned int vtx_index = draw_list->_VtxCurrentIdx;
const ImU32 col_untinted = col | ~IM_COL32_A_MASK; const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
const char* word_wrap_eol = NULL; const char* word_wrap_eol = NULL;
@ -3642,15 +3651,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
// Decode and advance source // Decode and advance source
unsigned int c = (unsigned int)*s; unsigned int c = (unsigned int)*s;
if (c < 0x80) if (c < 0x80)
{
s += 1; s += 1;
}
else else
{
s += ImTextCharFromUtf8(&c, s, text_end); s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}
if (c < 32) if (c < 32)
{ {
@ -3721,14 +3724,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
// We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
{ {
idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);
idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);
vtx_write += 4; vtx_write += 4;
vtx_current_idx += 4; vtx_index += 4;
idx_write += 6; idx_write += 6;
} }
} }
@ -3742,7 +3745,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
draw_list->_VtxWritePtr = vtx_write; draw_list->_VtxWritePtr = vtx_write;
draw_list->_IdxWritePtr = idx_write; draw_list->_IdxWritePtr = idx_write;
draw_list->_VtxCurrentIdx = vtx_current_idx; draw_list->_VtxCurrentIdx = vtx_index;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -1,10 +1,12 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (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 Dear ImGui features but we don't provide any guarantee of forward compatibility.
// Set: // To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use:
// #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) #define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui_internal.h"
*/
/* /*
@ -326,8 +328,8 @@ namespace ImStb
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Helpers: Hashing // Helpers: Hashing
IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImU32 seed = 0); IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0);
IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0);
// Helpers: Sorting // Helpers: Sorting
#ifndef ImQsort #ifndef ImQsort
@ -558,9 +560,12 @@ struct IMGUI_API ImRect
bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); }
}; };
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helper: ImBitArray // Helper: ImBitArray
#define IM_BITARRAY_TESTBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly!
#define IM_BITARRAY_CLEARBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31)))) // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly!
inline size_t ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; }
inline void ImBitArrayClearAllBits(ImU32* arr, int bitcount){ memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); }
inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; }
inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; }
inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; }
@ -577,6 +582,8 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran
} }
} }
typedef ImU32* ImBitArrayPtr; // Name for use in structs
// Helper: ImBitArray class (wrapper over ImBitArray functions) // Helper: ImBitArray class (wrapper over ImBitArray functions)
// Store 1-bit per value. // Store 1-bit per value.
template<int BITCOUNT, int OFFSET = 0> template<int BITCOUNT, int OFFSET = 0>
@ -586,11 +593,11 @@ struct ImBitArray
ImBitArray() { ClearAllBits(); } ImBitArray() { ClearAllBits(); }
void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }
void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } void SetAllBits() { memset(Storage, 255, sizeof(Storage)); }
bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }
void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); }
void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); }
void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2)
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }
}; };
// Helper: ImBitVector // Helper: ImBitVector
@ -600,10 +607,11 @@ struct IMGUI_API ImBitVector
ImVector<ImU32> Storage; ImVector<ImU32> Storage;
void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
void Clear() { Storage.clear(); } void Clear() { Storage.clear(); }
bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); }
void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }
void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }
}; };
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helper: ImSpan<> // Helper: ImSpan<>
// Pointing to a span of data we don't own. // Pointing to a span of data we don't own.
@ -1773,6 +1781,7 @@ struct ImGuiWindowSettings
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
bool Collapsed; bool Collapsed;
bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
bool WantDelete; // Set to invalidate/delete the settings entry
ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); DockOrder = -1; } ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); DockOrder = -1; }
char* GetName() { return (char*)(this + 1); } char* GetName() { return (char*)(this + 1); }
@ -1840,25 +1849,17 @@ enum ImGuiDebugLogFlags_
struct ImGuiMetricsConfig struct ImGuiMetricsConfig
{ {
bool ShowDebugLog; bool ShowDebugLog = false;
bool ShowStackTool; bool ShowStackTool = false;
bool ShowWindowsRects; bool ShowWindowsRects = false;
bool ShowWindowsBeginOrder; bool ShowWindowsBeginOrder = false;
bool ShowTablesRects; bool ShowTablesRects = false;
bool ShowDrawCmdMesh; bool ShowDrawCmdMesh = true;
bool ShowDrawCmdBoundingBoxes; bool ShowDrawCmdBoundingBoxes = true;
bool ShowDockingNodes; bool ShowAtlasTintedWithTextColor = false;
int ShowWindowsRectsType; bool ShowDockingNodes = false;
int ShowTablesRectsType; int ShowWindowsRectsType = -1;
int ShowTablesRectsType = -1;
ImGuiMetricsConfig()
{
ShowDebugLog = ShowStackTool = ShowWindowsRects = ShowWindowsBeginOrder = ShowTablesRects = false;
ShowDrawCmdMesh = true;
ShowDrawCmdBoundingBoxes = true;
ShowDockingNodes = false;
ShowWindowsRectsType = ShowTablesRectsType = -1;
}
}; };
struct ImGuiStackLevelInfo struct ImGuiStackLevelInfo
@ -2133,9 +2134,11 @@ struct ImGuiContext
ImFont InputTextPasswordFont; ImFont InputTextPasswordFont;
ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets
float ColorEditLastHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others).
float ColorEditLastSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for
ImU32 ColorEditLastColor; // RGB value with alpha set to 0. float ColorEditSavedHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips
float ColorEditSavedSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips
ImU32 ColorEditSavedColor; // RGB value with alpha set to 0.
ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker.
ImGuiComboPreviewData ComboPreviewData; ImGuiComboPreviewData ComboPreviewData;
float SliderGrabClickOffset; float SliderGrabClickOffset;
@ -2334,8 +2337,9 @@ struct ImGuiContext
TempInputId = 0; TempInputId = 0;
ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
ColorEditLastHue = ColorEditLastSat = 0.0f; ColorEditCurrentID = ColorEditSavedID = 0;
ColorEditLastColor = 0; ColorEditSavedHue = ColorEditSavedSat = 0.0f;
ColorEditSavedColor = 0;
SliderGrabClickOffset = 0.0f; SliderGrabClickOffset = 0.0f;
SliderCurrentAccum = 0.0f; SliderCurrentAccum = 0.0f;
SliderCurrentAccumDirty = false; SliderCurrentAccumDirty = false;
@ -2615,7 +2619,7 @@ struct ImGuiTabItem
float RequestedWidth; // Width optionally requested by caller, -1.0f is unused float RequestedWidth; // Width optionally requested by caller, -1.0f is unused
ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
ImS16 IndexDuringLayout; // Index only used during TabBarLayout() ImS16 IndexDuringLayout; // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions.
bool WantClose; // Marked as closed by SetTabItemClosed() bool WantClose; // Marked as closed by SetTabItemClosed()
ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; }
@ -2657,14 +2661,6 @@ struct IMGUI_API ImGuiTabBar
ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer.
ImGuiTabBar(); ImGuiTabBar();
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
const char* GetTabName(const ImGuiTabItem* tab) const
{
if (tab->Window)
return tab->Window->Name;
IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size);
return TabsNames.Buf.Data + tab->NameOffset;
}
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2672,12 +2668,11 @@ struct IMGUI_API ImGuiTabBar
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. #define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted
#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels()
// Our current column maximum is 64 but we may raise that in the future. // Our current column maximum is 64 but we may raise that in the future.
typedef ImS8 ImGuiTableColumnIdx; typedef ImS16 ImGuiTableColumnIdx;
typedef ImU8 ImGuiTableDrawChannelIdx; typedef ImU16 ImGuiTableDrawChannelIdx;
// [Internal] sizeof() ~ 104 // [Internal] sizeof() ~ 104
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
@ -2748,14 +2743,15 @@ struct ImGuiTableCellData
ImGuiTableColumnIdx Column; // Column number ImGuiTableColumnIdx Column; // Column number
}; };
// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs, does that needs they could be moved to ImGuiTableTempData ?) // Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?)
struct ImGuiTableInstanceData struct ImGuiTableInstanceData
{ {
ImGuiID TableInstanceID;
float LastOuterHeight; // Outer height from last frame float LastOuterHeight; // Outer height from last frame
float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked) float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked)
float LastFrozenHeight; // Height of frozen section from last frame float LastFrozenHeight; // Height of frozen section from last frame
ImGuiTableInstanceData() { LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; } ImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; }
}; };
// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData // FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData
@ -2768,10 +2764,9 @@ struct IMGUI_API ImGuiTable
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[] ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row. ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map ImBitArrayPtr EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data ImBitArrayPtr EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) ImBitArrayPtr VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items)
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
int SettingsOffset; // Offset in g.SettingsTables int SettingsOffset; // Offset in g.SettingsTables
int LastFrameActive; int LastFrameActive;
@ -3007,13 +3002,16 @@ namespace ImGui
IMGUI_API void MarkIniSettingsDirty(); IMGUI_API void MarkIniSettingsDirty();
IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window);
IMGUI_API void ClearIniSettings(); IMGUI_API void ClearIniSettings();
IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name);
IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id);
IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name);
IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler);
IMGUI_API void RemoveSettingsHandler(const char* type_name); IMGUI_API void RemoveSettingsHandler(const char* type_name);
IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);
// Settings - Windows
IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name);
IMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id);
IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window);
IMGUI_API void ClearWindowSettings(const char* name);
// Localization // Localization
IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count);
inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; } inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; }
@ -3046,6 +3044,7 @@ namespace ImGui
IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function.
IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes)
IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed);
IMGUI_API ImGuiID GetIDWithSeed(int n, ImGuiID seed);
// Basic Helpers for widget code // Basic Helpers for widget code
IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);
@ -3200,6 +3199,8 @@ namespace ImGui
IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer); IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer);
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window); IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
IMGUI_API void DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref = true);
IMGUI_API void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos); IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos);
IMGUI_API ImGuiDockNode*DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id); IMGUI_API ImGuiDockNode*DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode* node); IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode* node);
@ -3294,6 +3295,7 @@ namespace ImGui
IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table);
IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; }
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
@ -3305,7 +3307,7 @@ namespace ImGui
IMGUI_API void TableEndCell(ImGuiTable* table); IMGUI_API void TableEndCell(ImGuiTable* table);
IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);
IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
@ -3324,14 +3326,20 @@ namespace ImGui
IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);
// Tab Bars // Tab Bars
inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; }
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node); IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node);
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order);
IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar); IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar);
IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar);
inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); }
IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window); IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window);
IMGUI_API void TabBarRemoveTab(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 TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset); IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos); IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset);
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos);
IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar);
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window);
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker);
@ -3368,8 +3376,9 @@ namespace ImGui
IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
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);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0);
IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col); IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0);
IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width);
IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value);
IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value);
@ -3424,7 +3433,7 @@ namespace ImGui
IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags);
// Plot // Plot
IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg);
// Shade functions (write over already created vertices) // Shade functions (write over already created vertices)
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (tables and columns code) // (tables and columns code)
/* /*
@ -315,7 +315,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
return false; return false;
// Sanity checks // Sanity checks
IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!"); IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS);
if (flags & ImGuiTableFlags_ScrollX) if (flags & ImGuiTableFlags_ScrollX)
IM_ASSERT(inner_width >= 0.0f); IM_ASSERT(inner_width >= 0.0f);
@ -332,11 +332,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Acquire storage for the table // Acquire storage for the table
ImGuiTable* table = g.Tables.GetOrAddByKey(id); ImGuiTable* table = g.Tables.GetOrAddByKey(id);
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
const ImGuiID instance_id = id + instance_no;
const ImGuiTableFlags table_last_flags = table->Flags; const ImGuiTableFlags table_last_flags = table->Flags;
if (instance_no > 0)
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
// Acquire temporary buffers // Acquire temporary buffers
const int table_idx = g.Tables.GetIndex(table); const int table_idx = g.Tables.GetIndex(table);
@ -352,17 +348,32 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
flags = TableFixFlags(flags, outer_window); flags = TableFixFlags(flags, outer_window);
// Initialize // Initialize
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
table->ID = id; table->ID = id;
table->Flags = flags; table->Flags = flags;
table->InstanceCurrent = (ImS16)instance_no;
table->LastFrameActive = g.FrameCount; table->LastFrameActive = g.FrameCount;
table->OuterWindow = table->InnerWindow = outer_window; table->OuterWindow = table->InnerWindow = outer_window;
table->ColumnsCount = columns_count; table->ColumnsCount = columns_count;
table->IsLayoutLocked = false; table->IsLayoutLocked = false;
table->InnerWidth = inner_width; table->InnerWidth = inner_width;
temp_data->UserOuterSize = outer_size; temp_data->UserOuterSize = outer_size;
if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no)
// Instance data (for instance 0, TableID == TableInstanceID)
ImGuiID instance_id;
table->InstanceCurrent = (ImS16)instance_no;
if (instance_no > 0)
{
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
if (table->InstanceDataExtra.Size < instance_no)
table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); table->InstanceDataExtra.push_back(ImGuiTableInstanceData());
instance_id = GetIDWithSeed(instance_no, GetIDWithSeed("##Instances", NULL, id)); // Push "##Instance" followed by (int)instance_no in ID stack.
}
else
{
instance_id = id;
}
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
table_instance->TableInstanceID = instance_id;
// When not using a child window, WorkRect.Max will grow as we append contents. // When not using a child window, WorkRect.Max will grow as we append contents.
if (use_child_window) if (use_child_window)
@ -412,7 +423,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
} }
// Push a standardized ID for both child-using and not-child-using tables // Push a standardized ID for both child-using and not-child-using tables
PushOverrideID(instance_id); PushOverrideID(id);
if (instance_no > 0)
PushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol.
// Backup a copy of host window members we will modify // Backup a copy of host window members we will modify
ImGuiWindow* inner_window = table->InnerWindow; ImGuiWindow* inner_window = table->InnerWindow;
@ -581,16 +594,22 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)
{ {
// Allocate single buffer for our arrays // Allocate single buffer for our arrays
ImSpanAllocator<3> span_allocator; const int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count);
ImSpanAllocator<6> span_allocator;
span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn));
span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4);
for (int n = 3; n < 6; n++)
span_allocator.Reserve(n, columns_bit_array_size);
table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());
memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());
span_allocator.SetArenaBasePtr(table->RawData); span_allocator.SetArenaBasePtr(table->RawData);
span_allocator.GetSpan(0, &table->Columns); span_allocator.GetSpan(0, &table->Columns);
span_allocator.GetSpan(1, &table->DisplayOrderToIndex); span_allocator.GetSpan(1, &table->DisplayOrderToIndex);
span_allocator.GetSpan(2, &table->RowCellData); span_allocator.GetSpan(2, &table->RowCellData);
table->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3);
table->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4);
table->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5);
} }
// Apply queued resizing/reordering/hiding requests // Apply queued resizing/reordering/hiding requests
@ -729,8 +748,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
table->IsDefaultDisplayOrder = true; table->IsDefaultDisplayOrder = true;
table->ColumnsEnabledCount = 0; table->ColumnsEnabledCount = 0;
table->EnabledMaskByIndex = 0x00; ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount);
table->EnabledMaskByDisplayOrder = 0x00; ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount);
table->LeftMostEnabledColumn = -1; table->LeftMostEnabledColumn = -1;
table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
@ -795,8 +814,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
else else
table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;
column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
table->EnabledMaskByIndex |= (ImU64)1 << column_n; ImBitArraySetBit(table->EnabledMaskByIndex, column_n);
table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; ImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder);
prev_visible_column_idx = column_n; prev_visible_column_idx = column_n;
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
@ -844,7 +863,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
continue; continue;
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
@ -860,7 +879,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
if (column->AutoFitQueue != 0x00) if (column->AutoFitQueue != 0x00)
column->WidthRequest = width_auto; column->WidthRequest = width_auto;
else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n))) else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput)
column->WidthRequest = width_auto; column->WidthRequest = width_auto;
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
@ -908,7 +927,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
continue; continue;
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
@ -935,7 +954,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
{ {
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue; continue;
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))
@ -966,8 +985,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
ImRect host_clip_rect = table->InnerClipRect; ImRect host_clip_rect = table->InnerClipRect;
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
table->VisibleMaskByIndex = 0x00; ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount);
table->RequestOutputMaskByIndex = 0x00;
for (int order_n = 0; order_n < table->ColumnsCount; order_n++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{ {
const int column_n = table->DisplayOrderToIndex[order_n]; const int column_n = table->DisplayOrderToIndex[order_n];
@ -984,7 +1002,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Clear status flags // Clear status flags
column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; column->Flags &= ~ImGuiTableColumnFlags_StatusMask_;
if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
{ {
// Hidden column: clear a few fields and we are done with it for the remainder of the function. // Hidden column: clear a few fields and we are done with it for the remainder of the function.
// We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper.
@ -1037,12 +1055,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y);
const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;
if (is_visible) if (is_visible)
table->VisibleMaskByIndex |= ((ImU64)1 << column_n); ImBitArraySetBit(table->VisibleMaskByIndex, column_n);
// Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output.
column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;
if (column->IsRequestOutput)
table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n);
// Mark column as SkipItems (ignoring all items/layout) // Mark column as SkipItems (ignoring all items/layout)
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
@ -1128,12 +1144,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
EndPopup(); EndPopup();
} }
// [Part 13] Sanitize and build sort specs before we have a change to use them for display. // [Part 12] Sanitize and build sort specs before we have a change to use them for display.
// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)
if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable))
TableSortSpecsBuild(table); TableSortSpecsBuild(table);
// [Part 14] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns)
if (table->FreezeColumnsRequest > 0) if (table->FreezeColumnsRequest > 0)
table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x;
if (table->FreezeRowsRequest > 0) if (table->FreezeRowsRequest > 0)
@ -1169,7 +1185,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
for (int order_n = 0; order_n < table->ColumnsCount; order_n++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{ {
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue; continue;
const int column_n = table->DisplayOrderToIndex[order_n]; const int column_n = table->DisplayOrderToIndex[order_n];
@ -1305,7 +1321,7 @@ void ImGui::EndTable()
float auto_fit_width_for_stretched = 0.0f; float auto_fit_width_for_stretched = 0.0f;
float auto_fit_width_for_stretched_min = 0.0f; float auto_fit_width_for_stretched_min = 0.0f;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n)) if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
{ {
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);
@ -1345,8 +1361,10 @@ void ImGui::EndTable()
} }
// Pop from id stack // Pop from id stack
IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!");
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
if (table->InstanceCurrent > 0)
PopID();
PopID(); PopID();
// Restore window data that we modified // Restore window data that we modified
@ -1616,11 +1634,11 @@ ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
} }
// Return the resizing ID for the right-side of the given column. // Return the resizing ID for the right-side of the given column.
ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) ImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no)
{ {
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; ImGuiID instance_id = TableGetInstanceID(table, instance_no);
return id; return instance_id + 1 + column_n; // FIXME: #6140: still not ideal
} }
// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. // Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
@ -1651,7 +1669,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n
return; return;
if (column_n == -1) if (column_n == -1)
column_n = table->CurrentColumn; column_n = table->CurrentColumn;
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))
return; return;
if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
table->RowCellDataCurrent++; table->RowCellDataCurrent++;
@ -1926,7 +1944,7 @@ bool ImGui::TableSetColumnIndex(int column_n)
// Return whether the column is visible. User may choose to skip submitting items based on this return value, // Return whether the column is visible. User may choose to skip submitting items based on this return value,
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height. // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; return table->Columns[column_n].IsRequestOutput;
} }
// [Public] Append into the next column, wrap and create a new row when already on last column // [Public] Append into the next column, wrap and create a new row when already on last column
@ -1951,8 +1969,7 @@ bool ImGui::TableNextColumn()
// Return whether the column is visible. User may choose to skip submitting items based on this return value, // Return whether the column is visible. User may choose to skip submitting items based on this return value,
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height. // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
int column_n = table->CurrentColumn; return table->Columns[table->CurrentColumn].IsRequestOutput;
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
} }
@ -2292,7 +2309,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1;
const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount; const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount;
const int channels_for_bg = 1 + 1 * freeze_row_multiplier; const int channels_for_bg = 1 + 1 * freeze_row_multiplier;
const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0; const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0;
const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;
table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total);
table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1);
@ -2368,17 +2385,24 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
{ {
ImRect ClipRect; ImRect ClipRect;
int ChannelsCount; int ChannelsCount;
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> ChannelsMask; ImBitArrayPtr ChannelsMask;
MergeGroup() { ChannelsCount = 0; }
}; };
int merge_group_mask = 0x00; int merge_group_mask = 0x00;
MergeGroup merge_groups[4]; MergeGroup merge_groups[4] = {};
// Use a reusable temp buffer for the merge masks as they are dynamically sized.
const int max_draw_channels = (4 + table->ColumnsCount * 2);
const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels);
g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5);
memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5);
for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++)
merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n));
ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4));
// 1. Scan channels and take note of those which can be merged // 1. Scan channels and take note of those which can be merged
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))
continue; continue;
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
@ -2410,11 +2434,11 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
} }
const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2);
IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS); IM_ASSERT(channel_no < max_draw_channels);
MergeGroup* merge_group = &merge_groups[merge_group_n]; MergeGroup* merge_group = &merge_groups[merge_group_n];
if (merge_group->ChannelsCount == 0) if (merge_group->ChannelsCount == 0)
merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
merge_group->ChannelsMask.SetBit(channel_no); ImBitArraySetBit(merge_group->ChannelsMask, channel_no);
merge_group->ChannelsCount++; merge_group->ChannelsCount++;
merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect);
merge_group_mask |= (1 << merge_group_n); merge_group_mask |= (1 << merge_group_n);
@ -2450,9 +2474,8 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
const int LEADING_DRAW_CHANNELS = 2; const int LEADING_DRAW_CHANNELS = 2;
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask; // We need 132-bit of storage ImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count);
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); ImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen);
remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS); int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS);
//ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect; //ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect;
@ -2485,14 +2508,14 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200));
#endif #endif
remaining_count -= merge_group->ChannelsCount; remaining_count -= merge_group->ChannelsCount;
for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++) for (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++)
remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n]; remaining_mask[n] &= ~merge_group->ChannelsMask[n];
for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)
{ {
// Copy + overwrite new clip rect // Copy + overwrite new clip rect
if (!merge_group->ChannelsMask.TestBit(n)) if (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n))
continue; continue;
merge_group->ChannelsMask.ClearBit(n); IM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n);
merge_channels_count--; merge_channels_count--;
ImDrawChannel* channel = &splitter->_Channels[n]; ImDrawChannel* channel = &splitter->_Channels[n];
@ -2510,7 +2533,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
// Append unmergeable channels that we didn't reorder at the end of the list // Append unmergeable channels that we didn't reorder at the end of the list
for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) for (int n = 0; n < splitter->_Count && remaining_count != 0; n++)
{ {
if (!remaining_mask.TestBit(n)) if (!IM_BITARRAY_TESTBIT(remaining_mask, n))
continue; continue;
ImDrawChannel* channel = &splitter->_Channels[n]; ImDrawChannel* channel = &splitter->_Channels[n];
memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); memcpy(dst_tmp++, channel, sizeof(ImDrawChannel));
@ -2542,7 +2565,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
{ {
for (int order_n = 0; order_n < table->ColumnsCount; order_n++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{ {
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue; continue;
const int column_n = table->DisplayOrderToIndex[order_n]; const int column_n = table->DisplayOrderToIndex[order_n];
@ -2870,10 +2893,9 @@ void ImGui::TableHeadersRow()
continue; continue;
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
// - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.
// - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier.
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
PushID(table->InstanceCurrent * table->ColumnsCount + column_n); PushID(column_n);
TableHeader(name); TableHeader(name);
PopID(); PopID();
} }

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.2 // dear imgui, v1.89.3
// (widgets code) // (widgets code)
/* /*
@ -274,7 +274,6 @@ void ImGui::TextV(const char* fmt, va_list args)
if (window->SkipItems) if (window->SkipItems)
return; return;
// FIXME-OPT: Handle the %s shortcut?
const char* text, *text_end; const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args); ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
@ -291,9 +290,6 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
{ {
PushStyleColor(ImGuiCol_Text, col); PushStyleColor(ImGuiCol_Text, col);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args); TextV(fmt, args);
PopStyleColor(); PopStyleColor();
} }
@ -310,9 +306,6 @@ void ImGui::TextDisabledV(const char* fmt, va_list args)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args); TextV(fmt, args);
PopStyleColor(); PopStyleColor();
} }
@ -328,12 +321,9 @@ void ImGui::TextWrapped(const char* fmt, ...)
void ImGui::TextWrappedV(const char* fmt, va_list args) void ImGui::TextWrappedV(const char* fmt, va_list args)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
if (need_backup) if (need_backup)
PushTextWrapPos(0.0f); PushTextWrapPos(0.0f);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args); TextV(fmt, args);
if (need_backup) if (need_backup)
PopTextWrapPos(); PopTextWrapPos();
@ -1048,7 +1038,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2&
// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) // ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390)
// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. // We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API.
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -1062,7 +1052,7 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size
return false; return false;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@ -1400,6 +1390,7 @@ void ImGui::AlignTextToFramePadding()
} }
// Horizontal/vertical separating line // Horizontal/vertical separating line
// FIXME: Surprisingly, this seemingly simple widget is adjacent to MANY different legacy/tricky layout issues.
void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -1409,20 +1400,19 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected
float thickness_draw = 1.0f; const float thickness = 1.0f; // Cannot use g.Style.SeparatorTextSize yet for various reasons.
float thickness_layout = 0.0f;
if (flags & ImGuiSeparatorFlags_Vertical) if (flags & ImGuiSeparatorFlags_Vertical)
{ {
// Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. // Vertical separator, for menu bars (use current line height).
float y1 = window->DC.CursorPos.y; float y1 = window->DC.CursorPos.y;
float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y;
const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2));
ItemSize(ImVec2(thickness_layout, 0.0f)); ItemSize(ImVec2(thickness, 0.0f));
if (!ItemAdd(bb, 0)) if (!ItemAdd(bb, 0))
return; return;
// Draw // Draw
window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));
if (g.LogEnabled) if (g.LogEnabled)
LogText(" |"); LogText(" |");
} }
@ -1450,13 +1440,14 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
// We don't provide our width to the layout so that it doesn't get feed back into AutoFit // We don't provide our width to the layout so that it doesn't get feed back into AutoFit
// FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell)
const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change.
ItemSize(ImVec2(0.0f, thickness_layout)); const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness));
ItemSize(ImVec2(0.0f, thickness_for_layout));
const bool item_visible = ItemAdd(bb, 0); const bool item_visible = ItemAdd(bb, 0);
if (item_visible) if (item_visible)
{ {
// Draw // Draw
window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));
if (g.LogEnabled) if (g.LogEnabled)
LogRenderedText(&bb.Min, "--------------------------------\n"); LogRenderedText(&bb.Min, "--------------------------------\n");
@ -1482,6 +1473,71 @@ void ImGui::Separator()
SeparatorEx(flags); SeparatorEx(flags);
} }
void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = g.Style;
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImVec2 pos = window->DC.CursorPos;
const ImVec2 padding = style.SeparatorTextPadding;
const float separator_thickness = style.SeparatorTextBorderSize;
const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness));
const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y));
const float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f));
ItemSize(min_size, text_baseline_y);
if (!ItemAdd(bb, id))
return;
const float sep1_x1 = pos.x;
const float sep2_x2 = bb.Max.x;
const float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f);
const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f);
const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN
// This allows using SameLine() to position something in the 'extra_w'
window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x;
const ImU32 separator_col = GetColorU32(ImGuiCol_Separator);
if (label_size.x > 0.0f)
{
const float sep1_x2 = label_pos.x - style.ItemSpacing.x;
const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x;
if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness);
if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
if (g.LogEnabled)
LogSetNextTextDecoration("---", NULL);
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size);
}
else
{
if (g.LogEnabled)
LogText("---");
if (separator_thickness > 0.0f)
window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
}
}
void ImGui::SeparatorText(const char* label)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
// The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want:
// - allow headers to be draggable items (would require a stable ID + a noticeable highlight)
// - this high-level entry point to allow formatting? (may require ID separate from formatted string)
// - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...'
// Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item,
// and then we can turn this into a format function.
SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f);
}
// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. // Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise.
bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col)
{ {
@ -1711,7 +1767,12 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
constraint_min.x = w;
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
SetNextWindowSizeConstraints(constraint_min, constraint_max);
} }
// This is essentially a specialized version of BeginPopupEx() // This is essentially a specialized version of BeginPopupEx()
@ -4102,6 +4163,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863)
} }
const bool is_osx = io.ConfigMacOSXBehaviors;
if (g.ActiveId != id && init_make_active) if (g.ActiveId != id && init_make_active)
{ {
IM_ASSERT(state && state->ID == id); IM_ASSERT(state && state->ID == id);
@ -4124,6 +4186,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
SetKeyOwner(ImGuiKey_PageUp, id); SetKeyOwner(ImGuiKey_PageUp, id);
SetKeyOwner(ImGuiKey_PageDown, id); SetKeyOwner(ImGuiKey_PageDown, id);
} }
if (is_osx)
SetKeyOwner(ImGuiMod_Alt, id);
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character.
SetKeyOwner(ImGuiKey_Tab, id); SetKeyOwner(ImGuiKey_Tab, id);
} }
@ -4193,7 +4257,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f));
const bool is_osx = io.ConfigMacOSXBehaviors;
if (select_all) if (select_all)
{ {
state->SelectAll(); state->SelectAll();
@ -4294,7 +4357,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb.row_count_per_page = row_count_per_page; state->Stb.row_count_per_page = row_count_per_page;
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
const bool is_osx = io.ConfigMacOSXBehaviors;
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
@ -4323,7 +4385,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; }
else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut)
{
if (!state->HasSelection())
{
// OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace)
if (is_wordmove_key_down)
state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
}
state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask);
}
else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly)
{ {
if (!state->HasSelection()) if (!state->HasSelection())
@ -4413,12 +4484,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const int clipboard_len = (int)strlen(clipboard); const int clipboard_len = (int)strlen(clipboard);
ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar));
int clipboard_filtered_len = 0; int clipboard_filtered_len = 0;
for (const char* s = clipboard; *s; ) for (const char* s = clipboard; *s != 0; )
{ {
unsigned int c; unsigned int c;
s += ImTextCharFromUtf8(&c, s, NULL); s += ImTextCharFromUtf8(&c, s, NULL);
if (c == 0)
break;
if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard))
continue; continue;
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
@ -4868,7 +4937,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
ImStb::StbUndoState* undo_state = &stb_state->undostate; ImStb::StbUndoState* undo_state = &stb_state->undostate;
Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId);
DebugLocateItemOnHover(state->ID); DebugLocateItemOnHover(state->ID);
Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, state->CurLenW, stb_state->cursor, stb_state->select_start, stb_state->select_end); Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end);
Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x);
Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point);
if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state
@ -4916,28 +4985,32 @@ bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flag
return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);
} }
static void ColorEditRestoreH(const float* col, float* H)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.ColorEditCurrentID != 0);
if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))
return;
*H = g.ColorEditSavedHue;
}
// ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. // ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation.
// Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. // Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting.
static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V)
{ {
// This check is optional. Suppose we have two color widgets side by side, both widgets display different colors, but both colors have hue and/or saturation undefined.
// With color check: hue/saturation is preserved in one widget. Editing color in one widget would reset hue/saturation in another one.
// Without color check: common hue/saturation would be displayed in all widgets that have hue/saturation undefined.
// g.ColorEditLastColor is stored as ImU32 RGB value: this essentially gives us color equality check with reduced precision.
// Tiny external color changes would not be detected and this check would still pass. This is OK, since we only restore hue/saturation _only_ if they are undefined,
// therefore this change flipping hue/saturation from undefined to a very tiny value would still be represented in color picker.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.ColorEditLastColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) IM_ASSERT(g.ColorEditCurrentID != 0);
if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))
return; return;
// When S == 0, H is undefined. // When S == 0, H is undefined.
// When H == 1 it wraps around to 0. // When H == 1 it wraps around to 0.
if (*S == 0.0f || (*H == 0.0f && g.ColorEditLastHue == 1)) if (*S == 0.0f || (*H == 0.0f && g.ColorEditSavedHue == 1))
*H = g.ColorEditLastHue; *H = g.ColorEditSavedHue;
// When V == 0, S is undefined. // When V == 0, S is undefined.
if (*V == 0.0f) if (*V == 0.0f)
*S = g.ColorEditLastSat; *S = g.ColorEditSavedSat;
} }
// Edit colors components (each component in 0.0f..1.0f range). // Edit colors components (each component in 0.0f..1.0f range).
@ -4960,6 +5033,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
BeginGroup(); BeginGroup();
PushID(label); PushID(label);
const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0);
if (set_current_color_edit_id)
g.ColorEditCurrentID = window->IDStack.back();
// If we're not showing any slider there's no point in doing any HSV conversions // If we're not showing any slider there's no point in doing any HSV conversions
const ImGuiColorEditFlags flags_untouched = flags; const ImGuiColorEditFlags flags_untouched = flags;
@ -4993,7 +5069,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV))
{ {
// Hue is lost when converting from greyscale rgb (saturation=0). Restore it. // Hue is lost when converting from grayscale rgb (saturation=0). Restore it.
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); ColorEditRestoreHS(col, &f[0], &f[1], &f[2]);
} }
@ -5132,10 +5208,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
f[n] = i[n] / 255.0f; f[n] = i[n] / 255.0f;
if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB))
{ {
g.ColorEditLastHue = f[0]; g.ColorEditSavedHue = f[0];
g.ColorEditLastSat = f[1]; g.ColorEditSavedSat = f[1];
ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); g.ColorEditSavedID = g.ColorEditCurrentID;
g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0));
} }
if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV))
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
@ -5147,6 +5224,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
col[3] = f[3]; col[3] = f[3];
} }
if (set_current_color_edit_id)
g.ColorEditCurrentID = 0;
PopID(); PopID();
EndGroup(); EndGroup();
@ -5220,6 +5299,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
g.NextItemData.ClearFlags(); g.NextItemData.ClearFlags();
PushID(label); PushID(label);
const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0);
if (set_current_color_edit_id)
g.ColorEditCurrentID = window->IDStack.back();
BeginGroup(); BeginGroup();
if (!(flags & ImGuiColorEditFlags_NoSidePreview)) if (!(flags & ImGuiColorEditFlags_NoSidePreview))
@ -5268,7 +5350,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
float R = col[0], G = col[1], B = col[2]; float R = col[0], G = col[1], B = col[2];
if (flags & ImGuiColorEditFlags_InputRGB) if (flags & ImGuiColorEditFlags_InputRGB)
{ {
// Hue is lost when converting from greyscale rgb (saturation=0). Restore it. // Hue is lost when converting from grayscale rgb (saturation=0). Restore it.
ColorConvertRGBtoHSV(R, G, B, H, S, V); ColorConvertRGBtoHSV(R, G, B, H, S, V);
ColorEditRestoreHS(col, &H, &S, &V); ColorEditRestoreHS(col, &H, &S, &V);
} }
@ -5323,10 +5405,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
{ {
S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1));
V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square.
// Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square.
if (g.ColorEditLastColor == ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))
H = g.ColorEditLastHue;
value_changed = value_changed_sv = true; value_changed = value_changed_sv = true;
} }
if (!(flags & ImGuiColorEditFlags_NoOptions)) if (!(flags & ImGuiColorEditFlags_NoOptions))
@ -5401,9 +5480,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
if (flags & ImGuiColorEditFlags_InputRGB) if (flags & ImGuiColorEditFlags_InputRGB)
{ {
ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]); ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]);
g.ColorEditLastHue = H; g.ColorEditSavedHue = H;
g.ColorEditLastSat = S; g.ColorEditSavedSat = S;
g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); g.ColorEditSavedID = g.ColorEditCurrentID;
g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0));
} }
else if (flags & ImGuiColorEditFlags_InputHSV) else if (flags & ImGuiColorEditFlags_InputHSV)
{ {
@ -5567,6 +5647,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId
MarkItemEdited(g.LastItemData.ID); MarkItemEdited(g.LastItemData.ID);
if (set_current_color_edit_id)
g.ColorEditCurrentID = 0;
PopID(); PopID();
return value_changed; return value_changed;
@ -6555,7 +6637,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -6566,10 +6648,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (frame_size.x == 0.0f) const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
frame_size.x = CalcItemWidth();
if (frame_size.y == 0.0f)
frame_size.y = label_size.y + (style.FramePadding.y * 2);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
@ -7038,7 +7117,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
float w = label_size.x; float w = label_size.x;
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, 0.0f)); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y));
RenderText(text_pos, label); RenderText(text_pos, label);
PopStyleVar(); PopStyleVar();
window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
@ -7054,7 +7133,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
RenderText(text_pos, label); RenderText(text_pos, label);
if (icon_w > 0.0f) if (icon_w > 0.0f)
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
@ -7246,7 +7325,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
{ {
RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
@ -7298,12 +7377,19 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarCalcTabID() [Internal] // - TabBarCalcTabID() [Internal]
// - TabBarCalcMaxTabWidth() [Internal] // - TabBarCalcMaxTabWidth() [Internal]
// - TabBarFindTabById() [Internal] // - TabBarFindTabById() [Internal]
// - TabBarFindTabByOrder() [Internal]
// - TabBarFindMostRecentlySelectedTabForActiveWindow() [Internal]
// - TabBarGetCurrentTab() [Internal]
// - TabBarGetTabName() [Internal]
// - TabBarAddTab() [Internal] // - TabBarAddTab() [Internal]
// - TabBarRemoveTab() [Internal] // - TabBarRemoveTab() [Internal]
// - TabBarCloseTab() [Internal] // - TabBarCloseTab() [Internal]
// - TabBarScrollClamp() [Internal] // - TabBarScrollClamp() [Internal]
// - TabBarScrollToTab() [Internal] // - TabBarScrollToTab() [Internal]
// - TabBarQueueChangeTabOrder() [Internal] // - TabBarQueueFocus() [Internal]
// - TabBarQueueReorder() [Internal]
// - TabBarProcessReorderFromMousePos() [Internal]
// - TabBarProcessReorder() [Internal]
// - TabBarScrollingButtons() [Internal] // - TabBarScrollingButtons() [Internal]
// - TabBarTabListPopupButton() [Internal] // - TabBarTabListPopupButton() [Internal]
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -7429,6 +7515,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->ItemSpacingY = g.Style.ItemSpacing.y; tab_bar->ItemSpacingY = g.Style.ItemSpacing.y;
tab_bar->FramePadding = g.Style.FramePadding; tab_bar->FramePadding = g.Style.FramePadding;
tab_bar->TabsActiveCount = 0; tab_bar->TabsActiveCount = 0;
tab_bar->LastTabItemIdx = -1;
tab_bar->BeginCount = 1; tab_bar->BeginCount = 1;
// Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap
@ -7484,6 +7571,7 @@ void ImGui::EndTabBar()
if (tab_bar->BeginCount > 1) if (tab_bar->BeginCount > 1)
window->DC.CursorPos = tab_bar->BackupCursorPos; window->DC.CursorPos = tab_bar->BackupCursorPos;
tab_bar->LastTabItemIdx = -1;
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
PopID(); PopID();
@ -7593,7 +7681,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar.
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab); const char* tab_name = TabBarGetTabName(tab_bar, tab);
const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;
@ -7758,6 +7846,14 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
return NULL; return NULL;
} }
// Order = visible order, not submission order! (which is tab->BeginOrder)
ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order)
{
if (order < 0 || order >= tab_bar->Tabs.Size)
return NULL;
return &tab_bar->Tabs[order];
}
// FIXME: See references to #2304 in TODO.txt // FIXME: See references to #2304 in TODO.txt
ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar) ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar)
{ {
@ -7772,6 +7868,23 @@ ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBa
return most_recently_selected_tab; return most_recently_selected_tab;
} }
ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
{
if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)
return NULL;
return &tab_bar->Tabs[tab_bar->LastTabItemIdx];
}
const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
if (tab->Window)
return tab->Window->Name;
if (tab->NameOffset == -1)
return "N/A";
IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);
return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
}
// The purpose of this call is to register tab in advance so we can control their order at the time they appear. // The purpose of this call is to register tab in advance so we can control their order at the time they appear.
// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function. // Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window) void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
@ -7793,7 +7906,7 @@ void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGu
tab_bar->Tabs.push_back(new_tab); tab_bar->Tabs.push_back(new_tab);
} }
// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. // The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
{ {
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
@ -7824,7 +7937,7 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{ {
// Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup)
if (tab_bar->VisibleTabId != tab->ID) if (tab_bar->VisibleTabId != tab->ID)
tab_bar->NextSelectedTabId = tab->ID; TabBarQueueFocus(tab_bar, tab);
} }
} }
@ -7845,7 +7958,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
int order = tab_bar->GetTabOrder(tab); int order = TabBarGetTabOrder(tab_bar, tab);
// Scrolling happens only in the central section (leading/trailing sections are not scrolling) // Scrolling happens only in the central section (leading/trailing sections are not scrolling)
// FIXME: This is all confusing. // FIXME: This is all confusing.
@ -7869,7 +7982,12 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
} }
} }
void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset) void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
tab_bar->NextSelectedTabId = tab->ID;
}
void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset)
{ {
IM_ASSERT(offset != 0); IM_ASSERT(offset != 0);
IM_ASSERT(tab_bar->ReorderRequestTabId == 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
@ -7877,7 +7995,7 @@ void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, in
tab_bar->ReorderRequestOffset = (ImS16)offset; tab_bar->ReorderRequestOffset = (ImS16)offset;
} }
void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos) void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(tab_bar->ReorderRequestTabId == 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
@ -7920,7 +8038,7 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
return false; return false;
//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset; int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset;
if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
return false; return false;
@ -7980,7 +8098,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
if (select_dir != 0) if (select_dir != 0)
if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
{ {
int selected_order = tab_bar->GetTabOrder(tab_item); int selected_order = TabBarGetTabOrder(tab_bar, tab_item);
int target_order = selected_order + select_dir; int target_order = selected_order + select_dir;
// Skip tab item buttons until another tab item is found or end is reached // Skip tab item buttons until another tab item is found or end is reached
@ -8032,7 +8150,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
if (tab->Flags & ImGuiTabItemFlags_Button) if (tab->Flags & ImGuiTabItemFlags_Button)
continue; continue;
const char* tab_name = tab_bar->GetTabName(tab); const char* tab_name = TabBarGetTabName(tab_bar, tab);
if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))
tab_to_select = tab; tab_to_select = tab;
} }
@ -8199,9 +8317,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
{ {
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
tab_bar->NextSelectedTabId = id; // New tabs gets activated TabBarQueueFocus(tab_bar, tab); // New tabs gets activated
if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar
tab_bar->NextSelectedTabId = id; TabBarQueueFocus(tab_bar, tab);
} }
// Lock visibility // Lock visibility
@ -8265,7 +8383,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
if (pressed && !is_tab_button) if (pressed && !is_tab_button)
tab_bar->NextSelectedTabId = id; TabBarQueueFocus(tab_bar, tab);
// Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow() // Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow()
// will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id. // will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id.
@ -8322,7 +8440,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
if (distance_from_edge_y >= threshold_y) if (distance_from_edge_y >= threshold_y)
undocking_tab = true; undocking_tab = true;
if (drag_distance_from_edge_x > threshold_x) if (drag_distance_from_edge_x > threshold_x)
if ((drag_dir < 0 && tab_bar->GetTabOrder(tab) == 0) || (drag_dir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1)) if ((drag_dir < 0 && TabBarGetTabOrder(tab_bar, tab) == 0) || (drag_dir > 0 && TabBarGetTabOrder(tab_bar, tab) == tab_bar->Tabs.Size - 1))
undocking_tab = true; undocking_tab = true;
} }
@ -8358,9 +8476,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)
if (!is_tab_button) TabBarQueueFocus(tab_bar, tab);
tab_bar->NextSelectedTabId = id;
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;

View File

@ -24,7 +24,7 @@ See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad
- Oversampling settins are ignored but also not so much necessary with the higher quality rendering. - Oversampling settins are ignored but also not so much necessary with the higher quality rendering.
### Comparaison ### Comparison
Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting: Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting:
![comparing_font_rasterizers](https://user-images.githubusercontent.com/8225057/107550178-fef87f00-6bd0-11eb-8d09-e2edb2f0ccfc.gif) ![comparing_font_rasterizers](https://user-images.githubusercontent.com/8225057/107550178-fef87f00-6bd0-11eb-8d09-e2edb2f0ccfc.gif)

View File

@ -43,13 +43,16 @@
#include FT_SYNTHESIS_H // <freetype/ftsynth.h> #include FT_SYNTHESIS_H // <freetype/ftsynth.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
#endif #endif
#if defined(__GNUC__) #ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#pragma GCC diagnostic ignored "-Wsubobject-linkage" // warning: 'xxxx' has a field xxxx whose type uses the anonymous namespace
#endif #endif
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -348,7 +351,7 @@ namespace
IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
} }
} }
} } // namespace
#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
@ -441,7 +444,12 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); 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) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
{
// Check for valid range. This may also help detect *some* dangling pointers, because a common
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
IM_ASSERT(src_range[0] <= src_range[1]);
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
}
dst_tmp.SrcCount++; dst_tmp.SrcCount++;
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
} }
@ -779,3 +787,11 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u
GImGuiFreeTypeFreeFunc = free_func; GImGuiFreeTypeFreeFunc = free_func;
GImGuiFreeTypeAllocatorUserData = user_data; GImGuiFreeTypeAllocatorUserData = user_data;
} }
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning (pop)
#endif

View File

@ -1,7 +1,7 @@
// dear imgui: Platform Backend for GLFW // dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (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+. Prefer GLFW 3.3+ for full feature support.) // (Requires: GLFW 3.1+. Prefer GLFW 3.3+ or GLFW 3.4+ for full feature support.)
// Implemented features: // Implemented features:
// [X] Platform: Clipboard support. // [X] Platform: Clipboard support.
@ -21,6 +21,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)
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
// 2023-01-18: Handle unsupported glfwGetVideoMode() call on e.g. Emscripten.
// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty. // 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908) // 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785) // 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
@ -85,6 +87,11 @@
#include <GLFW/glfw3native.h> // for glfwGetCocoaWindow() #include <GLFW/glfw3native.h> // for glfwGetCocoaWindow()
#endif #endif
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
// We gather version tests as define in order to easily see which features are version-dependent. // We gather version tests as define in order to easily see which features are version-dependent.
#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING
@ -127,6 +134,7 @@ struct ImGui_ImplGlfw_Data
ImVec2 LastValidMousePos; ImVec2 LastValidMousePos;
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST]; GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
bool InstalledCallbacks; bool InstalledCallbacks;
bool CallbacksChainForAllWindows;
bool WantUpdateMonitors; bool WantUpdateMonitors;
#ifdef _WIN32 #ifdef _WIN32
WNDPROC GlfwWndProc; WNDPROC GlfwWndProc;
@ -298,10 +306,16 @@ static void ImGui_ImplGlfw_UpdateKeyModifiers()
io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(bd->Window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(bd->Window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
} }
static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
return bd->CallbacksChainForAllWindows ? true : (window == bd->Window);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackMousebutton != nullptr && window == bd->Window) if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackMousebutton(window, button, action, mods); bd->PrevUserCallbackMousebutton(window, button, action, mods);
ImGui_ImplGlfw_UpdateKeyModifiers(); ImGui_ImplGlfw_UpdateKeyModifiers();
@ -314,9 +328,14 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackScroll != nullptr && window == bd->Window) if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackScroll(window, xoffset, yoffset); bd->PrevUserCallbackScroll(window, xoffset, yoffset);
#ifdef __EMSCRIPTEN__
// Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
return;
#endif
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.AddMouseWheelEvent((float)xoffset, (float)yoffset); io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
} }
@ -357,7 +376,7 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackKey != nullptr && window == bd->Window) if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
if (action != GLFW_PRESS && action != GLFW_RELEASE) if (action != GLFW_PRESS && action != GLFW_RELEASE)
@ -379,7 +398,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackWindowFocus != nullptr && window == bd->Window) if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackWindowFocus(window, focused); bd->PrevUserCallbackWindowFocus(window, focused);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -389,7 +408,7 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorPos != nullptr && window == bd->Window) if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackCursorPos(window, x, y); bd->PrevUserCallbackCursorPos(window, x, y);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return; return;
@ -411,7 +430,7 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorEnter != nullptr && window == bd->Window) if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackCursorEnter(window, entered); bd->PrevUserCallbackCursorEnter(window, entered);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return; return;
@ -433,7 +452,7 @@ void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackChar != nullptr && window == bd->Window) if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
bd->PrevUserCallbackChar(window, c); bd->PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -446,6 +465,24 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
bd->WantUpdateMonitors = true; bd->WantUpdateMonitors = true;
} }
#ifdef __EMSCRIPTEN__
static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*)
{
// Mimic Emscripten_HandleWheel() in SDL.
// Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096
float multiplier = 0.0f;
if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step.
else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step.
else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps.
float wheel_x = ev->deltaX * -multiplier;
float wheel_y = ev->deltaY * -multiplier;
ImGuiIO& io = ImGui::GetIO();
io.AddMouseWheelEvent(wheel_x, wheel_y);
//IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y);
return EM_TRUE;
}
#endif
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
{ {
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@ -488,6 +525,16 @@ void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
bd->PrevUserCallbackMonitor = nullptr; bd->PrevUserCallbackMonitor = nullptr;
} }
// Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user.
// This is 'false' by default meaning we only chain callbacks for the main viewport.
// We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback.
// If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter.
void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
bd->CallbacksChainForAllWindows = chain_for_all_windows;
}
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)
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -542,18 +589,26 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
if (install_callbacks) if (install_callbacks)
ImGui_ImplGlfw_InstallCallbacks(window); ImGui_ImplGlfw_InstallCallbacks(window);
// Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
// We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
// FIXME: May break chaining in case user registered their own Emscripten callback?
#ifdef __EMSCRIPTEN__
emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, false, ImGui_ImplEmscripten_WheelCallback);
#endif
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors(); ImGui_ImplGlfw_UpdateMonitors();
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
// Our mouse update function expect PlatformHandle to be filled for the main viewport // Set platform dependent data in viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)bd->Window; main_viewport->PlatformHandle = (void*)bd->Window;
#ifdef _WIN32 #ifdef _WIN32
main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
#elif defined(__APPLE__) #elif defined(__APPLE__)
main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window);
#else
IM_UNUSED(main_viewport);
#endif #endif
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplGlfw_InitPlatformInterface(); ImGui_ImplGlfw_InitPlatformInterface();
@ -759,12 +814,15 @@ static void ImGui_ImplGlfw_UpdateMonitors()
int monitors_count = 0; int monitors_count = 0;
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
platform_io.Monitors.resize(0); platform_io.Monitors.resize(0);
bd->WantUpdateMonitors = false;
for (int n = 0; n < monitors_count; n++) for (int n = 0; n < monitors_count; n++)
{ {
ImGuiPlatformMonitor monitor; ImGuiPlatformMonitor monitor;
int x, y; int x, y;
glfwGetMonitorPos(glfw_monitors[n], &x, &y); glfwGetMonitorPos(glfw_monitors[n], &x, &y);
const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
if (vid_mode == NULL)
continue; // Failed to get Video mode (e.g. Emscripten does not support this function)
monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
#if GLFW_HAS_MONITOR_WORK_AREA #if GLFW_HAS_MONITOR_WORK_AREA
@ -784,7 +842,6 @@ static void ImGui_ImplGlfw_UpdateMonitors()
#endif #endif
platform_io.Monitors.push_back(monitor); platform_io.Monitors.push_back(monitor);
} }
bd->WantUpdateMonitors = false;
} }
void ImGui_ImplGlfw_NewFrame() void ImGui_ImplGlfw_NewFrame()

View File

@ -30,13 +30,17 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
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 (installer) // GLFW callbacks install
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any. // - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks. // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
// GLFW callbacks (individual callbacks to call if you didn't install callbacks) // GFLW callbacks options:
// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user)
IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows);
// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks)
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84 IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84 IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87 IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87

View File

@ -5,8 +5,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -114,6 +114,8 @@
#endif #endif
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types
#endif #endif

View File

@ -5,8 +5,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.