1
0
mirror of https://github.com/Drezil/imgui.git synced 2024-12-26 01:26:35 +00:00

Merge branch 'master' into docking

# Conflicts:
#	examples/imgui_impl_glfw.cpp
#	examples/imgui_impl_win32.cpp
#	imgui.cpp
#	imgui_internal.h
This commit is contained in:
omar 2019-05-13 19:23:18 +02:00
commit 4158cba1ff
15 changed files with 386 additions and 263 deletions

View File

@ -33,13 +33,25 @@ HOW TO UPDATE?
----------------------------------------------------------------------- -----------------------------------------------------------------------
Breaking Changes: Breaking Changes:
- IO: changed AddInputCharacter(unsigned short c) signature to AddInputCharacter(unsigned int c).
- Renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
Other Changes: Other Changes:
- Columns: Fixed Separator from creating an extraneous draw command. (#125) - Columns: Fixed Separator from creating an extraneous draw command. (#125)
- Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125)
- Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect
but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. but it breaks existing some layout patterns. Will return back to it when we expose Separator flags.
- Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple
times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000").
It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here.
- Fixed uses of IsItemDeactivated(), IsItemDeactivatedAfterEdit() on multi-components widgets and
after EndGroup(). (#2550, #1875)
- Scrollbar: Very minor bounding box adjustment to cope with various border size. - Scrollbar: Very minor bounding box adjustment to cope with various border size.
- ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545)
Combine with RasterizerFlags::MonoHinting for best results.
- Examples/Backends: Don't filter characters under 0x10000 before calling io.AddInputCharacter(),
the filtering is done in io.AddInputCharacter() itself. This is in prevision for fuller Unicode
support. (#2538, #2541)
----------------------------------------------------------------------- -----------------------------------------------------------------------

View File

@ -15,6 +15,7 @@
// 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)
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-11-30: Platform: Added touchscreen support. // 2018-11-30: Platform: Added touchscreen support.
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
@ -353,8 +354,7 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT *ev)
return true; return true;
case ALLEGRO_EVENT_KEY_CHAR: case ALLEGRO_EVENT_KEY_CHAR:
if (ev->keyboard.display == g_Display) if (ev->keyboard.display == g_Display)
if (ev->keyboard.unichar > 0 && ev->keyboard.unichar < 0x10000) io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
io.AddInputCharacter((unsigned short)ev->keyboard.unichar);
return true; return true;
case ALLEGRO_EVENT_KEY_DOWN: case ALLEGRO_EVENT_KEY_DOWN:
case ALLEGRO_EVENT_KEY_UP: case ALLEGRO_EVENT_KEY_UP:

View File

@ -17,6 +17,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
@ -131,8 +132,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
g_PrevUserCallbackChar(window, c); g_PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
if (c > 0 && c < 0x10000) io.AddInputCharacter(c);
io.AddInputCharacter((unsigned short)c);
} }
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)

View File

@ -118,7 +118,7 @@ void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
//printf("char_down_func %d '%c'\n", c, c); //printf("char_down_func %d '%c'\n", c, c);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
if (c >= 32) if (c >= 32)
io.AddInputCharacter((unsigned short)c); io.AddInputCharacter((unsigned int)c);
// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26. // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here. // This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.

View File

@ -12,6 +12,7 @@
// 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)
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
@ -166,8 +167,7 @@ int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data; s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
if ((e->m_Char > 0 && e->m_Char < 0x10000)) io.AddInputCharacter((unsigned int)e->m_Char);
io.AddInputCharacter((unsigned short)e->m_Char);
return 0; return 0;
} }

View File

@ -13,6 +13,7 @@
// 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)
// 2019-05-11: Inputs: Don't filter character values before calling AddInputCharacter() apart from 0xF700..0xFFFF range.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-07-07: Initial version. // 2018-07-07: Initial version.
@ -190,8 +191,8 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
int c = [str characterAtIndex:i]; int c = [str characterAtIndex:i];
if (c < 0xF700 && !io.KeyCtrl) if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF))
io.AddInputCharacter((unsigned short)c); io.AddInputCharacter((unsigned int)c);
// We must reset in case we're pressing a sequence of special keys while keeping the command pressed // We must reset in case we're pressing a sequence of special keys while keeping the command pressed
int key = mapCharacterToKey(c); int key = mapCharacterToKey(c);

View File

@ -20,6 +20,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. // 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. // 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
@ -361,8 +362,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
return 0; return 0;
case WM_CHAR: case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters. // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000) io.AddInputCharacter((unsigned int)wParam);
io.AddInputCharacter((unsigned short)wParam);
return 0; return 0;
case WM_SETCURSOR: case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())

192
imgui.cpp
View File

@ -380,6 +380,8 @@ CODE
- 2018/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. - 2018/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
- 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
- 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
- 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
- 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
- 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
@ -1289,9 +1291,10 @@ ImGuiIO::ImGuiIO()
// Pass in translated ASCII characters for text input. // Pass in translated ASCII characters for text input.
// - with glfw you can get those from the callback set in glfwSetCharCallback() // - with glfw you can get those from the callback set in glfwSetCharCallback()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
void ImGuiIO::AddInputCharacter(ImWchar c) void ImGuiIO::AddInputCharacter(unsigned int c)
{ {
InputQueueCharacters.push_back(c); if (c > 0 && c < 0x10000)
InputQueueCharacters.push_back((ImWchar)c);
} }
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
@ -1300,7 +1303,7 @@ 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 && c <= 0xFFFF) if (c > 0 && c < 0x10000)
InputQueueCharacters.push_back((ImWchar)c); InputQueueCharacters.push_back((ImWchar)c);
} }
} }
@ -2734,8 +2737,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
if (g.ActiveIdIsJustActivated) if (g.ActiveIdIsJustActivated)
{ {
g.ActiveIdTimer = 0.0f; g.ActiveIdTimer = 0.0f;
g.ActiveIdHasBeenPressed = false; g.ActiveIdHasBeenPressedBefore = false;
g.ActiveIdHasBeenEdited = false; g.ActiveIdHasBeenEditedBefore = false;
if (id != 0) if (id != 0)
{ {
g.LastActiveId = id; g.LastActiveId = id;
@ -2747,6 +2750,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdBlockNavInputFlags = 0; g.ActiveIdBlockNavInputFlags = 0;
g.ActiveIdAllowOverlap = false; g.ActiveIdAllowOverlap = false;
g.ActiveIdWindow = window; g.ActiveIdWindow = window;
g.ActiveIdHasBeenEditedThisFrame = false;
if (id) if (id)
{ {
g.ActiveIdIsAlive = id; g.ActiveIdIsAlive = id;
@ -2814,7 +2818,8 @@ void ImGui::MarkItemEdited(ImGuiID id)
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.ActiveIdHasBeenEdited = true; g.ActiveIdHasBeenEditedThisFrame = true;
g.ActiveIdHasBeenEditedBefore = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
} }
@ -2852,10 +2857,11 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
return; return;
// Always align ourselves on pixel boundaries // Always align ourselves on pixel boundaries
const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y); const float line_height = ImMax(window->DC.CurrLineSize.y, size.y);
const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); const float text_base_offset = ImMax(window->DC.CurrLineTextBaseOffset, text_offset_y);
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
@ -2864,7 +2870,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
window->DC.PrevLineSize.y = line_height; window->DC.PrevLineSize.y = line_height;
window->DC.PrevLineTextBaseOffset = text_base_offset; window->DC.PrevLineTextBaseOffset = text_base_offset;
window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f; window->DC.CurrLineSize.y = window->DC.CurrLineTextBaseOffset = 0.0f;
// Horizontal layout mode // Horizontal layout mode
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@ -2901,6 +2907,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
window->DC.LastItemId = id; window->DC.LastItemId = id;
window->DC.LastItemRect = bb; window->DC.LastItemRect = bb;
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0) if (id != 0)
@ -3704,8 +3711,9 @@ void ImGui::NewFrame()
g.LastActiveIdTimer += g.IO.DeltaTime; g.LastActiveIdTimer += g.IO.DeltaTime;
g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdPreviousFrame = g.ActiveId;
g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited; g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
g.ActiveIdIsAlive = 0; g.ActiveIdIsAlive = 0;
g.ActiveIdHasBeenEditedThisFrame = false;
g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdPreviousFrameIsAlive = false;
g.ActiveIdIsJustActivated = false; g.ActiveIdIsJustActivated = false;
if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId) if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId)
@ -4644,13 +4652,15 @@ bool ImGui::IsItemDeactivated()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
} }
bool ImGui::IsItemDeactivatedAfterEdit() bool ImGui::IsItemDeactivatedAfterEdit()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited)); return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
} }
bool ImGui::IsItemFocused() bool ImGui::IsItemFocused()
@ -4970,7 +4980,7 @@ static ImGuiWindow* GetWindowForTitleAndMenuHeight(ImGuiWindow* window)
static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.NextWindowData.SizeConstraintCond != 0) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
{ {
// Using -1,-1 on either X/Y axis to preserve the current size. // Using -1,-1 on either X/Y axis to preserve the current size.
ImRect cr = g.NextWindowData.SizeConstraintRect; ImRect cr = g.NextWindowData.SizeConstraintRect;
@ -5350,7 +5360,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
{ {
// Adjust alpha. For docking // Adjust alpha. For docking
float alpha = 1.0f; float alpha = 1.0f;
if (g.NextWindowData.BgAlphaCond != 0) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
alpha = g.NextWindowData.BgAlphaVal; alpha = g.NextWindowData.BgAlphaVal;
if (is_docking_transparent_payload) if (is_docking_transparent_payload)
alpha *= DOCKING_TRANSPARENT_PAYLOAD_ALPHA; alpha *= DOCKING_TRANSPARENT_PAYLOAD_ALPHA;
@ -5359,7 +5369,6 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
} }
window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
} }
g.NextWindowData.BgAlphaCond = 0;
// Title bar // Title bar
// (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag, // (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag,
@ -5513,7 +5522,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_is_fallback = (g.CurrentWindowStack.Size == 0); const bool window_is_fallback = (g.CurrentWindowStack.Size == 0);
if (window_just_created) if (window_just_created)
{ {
ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
window = CreateNewWindow(name, size_on_first_use, flags); window = CreateNewWindow(name, size_on_first_use, flags);
} }
@ -5557,7 +5566,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Docking // Docking
// (NB: during the frame dock nodes are created, it is possible that (window->DockIsActive == false) even though (window->DockNode->Windows.Size > 1) // (NB: during the frame dock nodes are created, it is possible that (window->DockIsActive == false) even though (window->DockNode->Windows.Size > 1)
IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); // Cannot be both IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); // Cannot be both
if (g.NextWindowData.DockCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasDock)
SetWindowDock(window, g.NextWindowData.DockId, g.NextWindowData.DockCond); SetWindowDock(window, g.NextWindowData.DockId, g.NextWindowData.DockCond);
if (first_begin_of_the_frame) if (first_begin_of_the_frame)
{ {
@ -5594,7 +5603,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Process SetNextWindow***() calls // Process SetNextWindow***() calls
bool window_pos_set_by_api = false; bool window_pos_set_by_api = false;
bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
if (g.NextWindowData.PosCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
{ {
window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
@ -5610,13 +5619,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
} }
} }
if (g.NextWindowData.SizeCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
{ {
window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
} }
if (g.NextWindowData.ContentSizeCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
{ {
// Adjust passed "client size" to become a "window size" // Adjust passed "client size" to become a "window size"
window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
@ -5627,10 +5636,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{ {
window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
} }
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasWindowClass)
window->WindowClass = g.NextWindowData.WindowClass; window->WindowClass = g.NextWindowData.WindowClass;
if (g.NextWindowData.CollapsedCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
if (g.NextWindowData.FocusCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
FocusWindow(window); FocusWindow(window);
if (window->Appearing) if (window->Appearing)
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
@ -6030,8 +6040,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPos = window->DC.CursorStartPos;
window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorPosPrevLine = window->DC.CursorPos;
window->DC.CursorMaxPos = window->DC.CursorStartPos; window->DC.CursorMaxPos = window->DC.CursorStartPos;
window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavHideHighlightOneFrame = false; window->DC.NavHideHighlightOneFrame = false;
window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f);
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
@ -6151,7 +6161,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->WriteAccessed = false; window->WriteAccessed = false;
window->BeginCount++; window->BeginCount++;
g.NextWindowData.Clear(); g.NextWindowData.ClearFlags();
// When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems. // When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems.
// This will have the important effect of actually returning true in Begin() and not setting SkipItems, allowing an earlier submission of the window contents. // This will have the important effect of actually returning true in Begin() and not setting SkipItems, allowing an earlier submission of the window contents.
@ -6368,20 +6378,24 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
void ImGui::SetNextItemWidth(float item_width) void ImGui::SetNextItemWidth(float item_width)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiContext& g = *GImGui;
window->DC.NextItemWidth = item_width; g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
g.NextItemData.Width = item_width;
} }
void ImGui::PushItemWidth(float item_width) void ImGui::PushItemWidth(float item_width)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
} }
void ImGui::PushMultiItemsWidths(int components, float w_full) void ImGui::PushMultiItemsWidths(int components, float w_full)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiStyle& style = GImGui->Style; const ImGuiStyle& style = GImGui->Style;
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
@ -6389,6 +6403,7 @@ void ImGui::PushMultiItemsWidths(int components, float w_full)
for (int i = 0; i < components-1; i++) for (int i = 0; i < components-1; i++)
window->DC.ItemWidthStack.push_back(w_item_one); window->DC.ItemWidthStack.push_back(w_item_one);
window->DC.ItemWidth = window->DC.ItemWidthStack.back(); window->DC.ItemWidth = window->DC.ItemWidthStack.back();
g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
} }
void ImGui::PopItemWidth() void ImGui::PopItemWidth()
@ -6398,21 +6413,17 @@ void ImGui::PopItemWidth()
window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
} }
// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(), // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
// Then consume the // The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
float ImGui::GetNextItemWidth() float ImGui::CalcItemWidth()
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float w; float w;
if (window->DC.NextItemWidth != FLT_MAX) if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
{ w = g.NextItemData.Width;
w = window->DC.NextItemWidth;
window->DC.NextItemWidth = FLT_MAX;
}
else else
{
w = window->DC.ItemWidth; w = window->DC.ItemWidth;
}
if (w < 0.0f) if (w < 0.0f)
{ {
float region_max_x = GetWorkRectMax().x; float region_max_x = GetWorkRectMax().x;
@ -6422,21 +6433,10 @@ float ImGui::GetNextItemWidth()
return w; return w;
} }
// Calculate item width *without* popping/consuming NextItemWidth if it was set. // [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
// (rarely used, which is why we avoid calling this from GetNextItemWidth() and instead do a backup/restore here)
float ImGui::CalcItemWidth()
{
ImGuiWindow* window = GImGui->CurrentWindow;
float backup_next_item_width = window->DC.NextItemWidth;
float w = GetNextItemWidth();
window->DC.NextItemWidth = backup_next_item_width;
return w;
}
// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == GetNextItemWidth().
// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. // Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
// Note that only CalcItemWidth() is publicly exposed. // Note that only CalcItemWidth() is publicly exposed.
// The 4.0f here may be changed to match GetNextItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiWindow* window = GImGui->CurrentWindow;
@ -6991,6 +6991,7 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
g.NextWindowData.PosVal = pos; g.NextWindowData.PosVal = pos;
g.NextWindowData.PosPivotVal = pivot; g.NextWindowData.PosPivotVal = pivot;
g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
@ -7010,6 +7011,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
g.NextWindowData.SizeVal = size; g.NextWindowData.SizeVal = size;
g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
} }
@ -7017,7 +7019,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.SizeConstraintCond = ImGuiCond_Always; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
g.NextWindowData.SizeCallback = custom_callback; g.NextWindowData.SizeCallback = custom_callback;
g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
@ -7026,14 +7028,15 @@ void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& s
void ImGui::SetNextWindowContentSize(const ImVec2& size) void ImGui::SetNextWindowContentSize(const ImVec2& size)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value. g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
} }
void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
g.NextWindowData.CollapsedVal = collapsed; g.NextWindowData.CollapsedVal = collapsed;
g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
} }
@ -7041,26 +7044,27 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
void ImGui::SetNextWindowFocus() void ImGui::SetNextWindowFocus()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
} }
void ImGui::SetNextWindowBgAlpha(float alpha) void ImGui::SetNextWindowBgAlpha(float alpha)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
g.NextWindowData.BgAlphaVal = alpha; g.NextWindowData.BgAlphaVal = alpha;
g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
} }
void ImGui::SetNextWindowViewport(ImGuiID id) void ImGui::SetNextWindowViewport(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.ViewportCond = ImGuiCond_Always; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasViewport;
g.NextWindowData.ViewportId = id; g.NextWindowData.ViewportId = id;
} }
void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond) void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasDock;
g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always; g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always;
g.NextWindowData.DockId = id; g.NextWindowData.DockId = id;
} }
@ -7068,6 +7072,7 @@ void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond)
void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class) void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasWindowClass;
g.NextWindowData.WindowClass = *window_class; g.NextWindowData.WindowClass = *window_class;
} }
@ -7420,16 +7425,16 @@ void ImGui::BeginGroup()
group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
group_data.BackupIndent = window->DC.Indent; group_data.BackupIndent = window->DC.Indent;
group_data.BackupGroupOffset = window->DC.GroupOffset; group_data.BackupGroupOffset = window->DC.GroupOffset;
group_data.BackupCurrentLineSize = window->DC.CurrentLineSize; group_data.BackupCurrLineSize = window->DC.CurrLineSize;
group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
group_data.AdvanceCursor = true; group_data.EmitItem = true;
window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
window->DC.Indent = window->DC.GroupOffset; window->DC.Indent = window->DC.GroupOffset;
window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorPos;
window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
if (g.LogEnabled) if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
} }
@ -7442,36 +7447,49 @@ void ImGui::EndGroup()
ImGuiGroupData& group_data = window->DC.GroupStack.back(); ImGuiGroupData& group_data = window->DC.GroupStack.back();
ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorPos = group_data.BackupCursorPos;
window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
window->DC.Indent = group_data.BackupIndent; window->DC.Indent = group_data.BackupIndent;
window->DC.GroupOffset = group_data.BackupGroupOffset; window->DC.GroupOffset = group_data.BackupGroupOffset;
window->DC.CurrentLineSize = group_data.BackupCurrentLineSize; window->DC.CurrLineSize = group_data.BackupCurrLineSize;
window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
if (g.LogEnabled) if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
if (group_data.AdvanceCursor) if (!group_data.EmitItem)
{ {
window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. window->DC.GroupStack.pop_back();
return;
}
window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize(group_bb.GetSize(), 0.0f); ItemSize(group_bb.GetSize(), 0.0f);
ItemAdd(group_bb, 0); ItemAdd(group_bb, 0);
}
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
// (and if you grep for LastItemId you'll notice it is only used in that context. // Also if you grep for LastItemId you'll notice it is only used in that context.
if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow) // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
if (group_contains_curr_active_id)
window->DC.LastItemId = g.ActiveId; window->DC.LastItemId = g.ActiveId;
else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow) else if (group_contains_prev_active_id)
window->DC.LastItemId = g.ActiveIdPreviousFrame; window->DC.LastItemId = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb; window->DC.LastItemRect = group_bb;
window->DC.GroupStack.pop_back(); // Forward Edited flag
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
// Forward Deactivated flag
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
window->DC.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
} }
@ -7499,8 +7517,8 @@ void ImGui::SameLine(float offset_from_start_x, float spacing_w)
window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
} }
window->DC.CurrentLineSize = window->DC.PrevLineSize; window->DC.CurrLineSize = window->DC.PrevLineSize;
window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
} }
void ImGui::Indent(float indent_w) void ImGui::Indent(float indent_w)
@ -7777,7 +7795,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (!IsPopupOpen(id)) if (!IsPopupOpen(id))
{ {
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false; return false;
} }
@ -7799,7 +7817,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
{ {
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false; return false;
} }
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking; flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking;
@ -7815,13 +7833,13 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
const ImGuiID id = window->GetID(name); const ImGuiID id = window->GetID(name);
if (!IsPopupOpen(id)) if (!IsPopupOpen(id))
{ {
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false; return false;
} }
// Center modal windows by default // Center modal windows by default
// FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
if (g.NextWindowData.PosCond == 0) if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
SetNextWindowPos(window->Viewport->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); SetNextWindowPos(window->Viewport->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking; flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking;
@ -9105,8 +9123,8 @@ void ImGui::NextColumn()
} }
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY; window->DC.CursorPos.y = columns->LineMinY;
window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrentLineTextBaseOffset = 0.0f; window->DC.CurrLineTextBaseOffset = 0.0f;
PushColumnClipRect(columns->Current); PushColumnClipRect(columns->Current);
PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup
@ -10589,7 +10607,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
window->ViewportId = 0; window->ViewportId = 0;
} }
if (!g.NextWindowData.ViewportCond) if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasViewport) == 0)
{ {
// By default inherit from parent window // By default inherit from parent window
if (window->Viewport == NULL && window->ParentWindow) if (window->Viewport == NULL && window->ParentWindow)
@ -10605,7 +10623,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
} }
bool lock_viewport = false; bool lock_viewport = false;
if (g.NextWindowData.ViewportCond) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasViewport)
{ {
// Code explicitly request a viewport // Code explicitly request a viewport
window->Viewport = (ImGuiViewportP*)FindViewportByID(g.NextWindowData.ViewportId); window->Viewport = (ImGuiViewportP*)FindViewportByID(g.NextWindowData.ViewportId);
@ -14286,7 +14304,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
continue; continue;
} }
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()),
"Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered()) if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered())
{ {
ImRect clip_rect = pcmd->ClipRect; ImRect clip_rect = pcmd->ClipRect;
@ -14387,7 +14407,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
static void NodeViewport(ImGuiViewportP* viewport) static void NodeViewport(ImGuiViewportP* viewport)
{ {
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once); ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A")) if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A"))
{ {
ImGuiWindowFlags flags = viewport->Flags; ImGuiWindowFlags flags = viewport->Flags;
@ -14522,7 +14542,7 @@ void ImGui::ShowDockingDebug()
static void NodeDockNode(ImGuiDockNode* node, const char* label) static void NodeDockNode(ImGuiDockNode* node, const char* label)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once); ImGui::SetNextItemOpen(true, ImGuiCond_Once);
bool open; bool open;
if (node->Windows.Size > 0) if (node->Windows.Size > 0)
open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");

12
imgui.h
View File

@ -506,9 +506,9 @@ namespace ImGui
IMGUI_API void TreePop(); // ~ Unindent()+PopId() IMGUI_API void TreePop(); // ~ Unindent()+PopId()
IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing()
IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode
IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().
IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
// Widgets: Selectables // Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected. // - A selectable highlights when hovered, and can display another color when selected.
@ -804,7 +804,8 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input)
ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
// [Internal] // [Internal]
ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline()
ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data
}; };
// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*()
@ -1244,7 +1245,7 @@ enum ImGuiMouseCursor_
#endif #endif
}; };
// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions // Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions
// Represent a condition. // Represent a condition.
// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always.
enum ImGuiCond_ enum ImGuiCond_
@ -1481,7 +1482,7 @@ struct ImGuiIO
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Functions // Functions
IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
@ -1621,6 +1622,9 @@ struct ImGuiWindowClass
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui namespace ImGui
{ {
// OBSOLETED in 1.71 (from May 2019)
static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
// OBSOLETED in 1.70 (from May 2019) // OBSOLETED in 1.70 (from May 2019)
static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; }
// OBSOLETED in 1.69 (from Mar 2019) // OBSOLETED in 1.69 (from Mar 2019)

View File

@ -623,6 +623,12 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Basic trees")) if (ImGui::TreeNode("Basic trees"))
{ {
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{
// Use SetNextItemOpen() so set the default state of a node to be open.
// We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
if (i == 0)
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
{ {
ImGui::Text("blah blah"); ImGui::Text("blah blah");
@ -630,6 +636,7 @@ static void ShowDemoWindowWidgets()
if (ImGui::SmallButton("button")) {}; if (ImGui::SmallButton("button")) {};
ImGui::TreePop(); ImGui::TreePop();
} }
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -1588,10 +1595,11 @@ static void ShowDemoWindowWidgets()
ImGui::RadioButton("Checkbox", &item_type, 2); ImGui::RadioButton("Checkbox", &item_type, 2);
ImGui::RadioButton("SliderFloat", &item_type, 3); ImGui::RadioButton("SliderFloat", &item_type, 3);
ImGui::RadioButton("InputText", &item_type, 4); ImGui::RadioButton("InputText", &item_type, 4);
ImGui::RadioButton("ColorEdit4", &item_type, 5); ImGui::RadioButton("InputFloat3", &item_type, 5);
ImGui::RadioButton("MenuItem", &item_type, 6); ImGui::RadioButton("ColorEdit4", &item_type, 6);
ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 7); ImGui::RadioButton("MenuItem", &item_type, 7);
ImGui::RadioButton("ListBox", &item_type, 8); ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 8);
ImGui::RadioButton("ListBox", &item_type, 9);
ImGui::Separator(); ImGui::Separator();
bool ret = false; bool ret = false;
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
@ -1599,10 +1607,11 @@ static void ShowDemoWindowWidgets()
if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
if (item_type == 5) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 5) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 6) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) if (item_type == 6) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 7) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. if (item_type == 7) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
if (item_type == 8) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } if (item_type == 8) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
if (item_type == 9) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
ImGui::BulletText( ImGui::BulletText(
"Return value = %d\n" "Return value = %d\n"
"IsItemFocused() = %d\n" "IsItemFocused() = %d\n"
@ -1683,6 +1692,9 @@ static void ShowDemoWindowWidgets()
if (embed_all_inside_a_child_window) if (embed_all_inside_a_child_window)
ImGui::EndChild(); ImGui::EndChild();
static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above.";
ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
// Calling IsItemHovered() after begin returns the hovered status of the title bar. // Calling IsItemHovered() after begin returns the hovered status of the title bar.
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
// This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).

View File

@ -74,7 +74,8 @@ struct ImGuiInputTextState; // Internal state of the currently focused/e
struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
struct ImGuiNavMoveResult; // Result of a directional navigation move query result struct ImGuiNavMoveResult; // Result of a directional navigation move query result
struct ImGuiNextWindowData; // Storage for SetNexWindow** functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
struct ImGuiNextItemData; // Storage for SetNextItem** functions
struct ImGuiPopupData; // Storage for current popup stack struct ImGuiPopupData; // Storage for current popup stack
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
@ -94,7 +95,9 @@ typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags:
typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d()
typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests
typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions
typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions
typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx()
typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior()
typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx()
@ -386,7 +389,9 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HoveredRect = 1 << 0, ImGuiItemStatusFlags_HoveredRect = 1 << 0,
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
ImGuiItemStatusFlags_ToggledSelection = 1 << 3 // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues.
ImGuiItemStatusFlags_HasDeactivated = 1 << 4, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
, // [imgui-test only] , // [imgui-test only]
@ -587,11 +592,11 @@ struct ImGuiGroupData
ImVec2 BackupCursorMaxPos; ImVec2 BackupCursorMaxPos;
ImVec1 BackupIndent; ImVec1 BackupIndent;
ImVec1 BackupGroupOffset; ImVec1 BackupGroupOffset;
ImVec2 BackupCurrentLineSize; ImVec2 BackupCurrLineSize;
float BackupCurrentLineTextBaseOffset; float BackupCurrLineTextBaseOffset;
ImGuiID BackupActiveIdIsAlive; ImGuiID BackupActiveIdIsAlive;
bool BackupActiveIdPreviousFrameIsAlive; bool BackupActiveIdPreviousFrameIsAlive;
bool AdvanceCursor; bool EmitItem;
}; };
// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. // Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
@ -793,17 +798,28 @@ struct ImGuiNavMoveResult
void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
}; };
enum ImGuiNextWindowDataFlags_
{
ImGuiNextWindowDataFlags_None = 0,
ImGuiNextWindowDataFlags_HasPos = 1 << 0,
ImGuiNextWindowDataFlags_HasSize = 1 << 1,
ImGuiNextWindowDataFlags_HasContentSize = 1 << 2,
ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3,
ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4,
ImGuiNextWindowDataFlags_HasFocus = 1 << 5,
ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6,
ImGuiNextWindowDataFlags_HasViewport = 1 << 7,
ImGuiNextWindowDataFlags_HasDock = 1 << 8,
ImGuiNextWindowDataFlags_HasWindowClass = 1 << 9
};
// Storage for SetNexWindow** functions // Storage for SetNexWindow** functions
struct ImGuiNextWindowData struct ImGuiNextWindowData
{ {
ImGuiNextWindowDataFlags Flags;
ImGuiCond PosCond; ImGuiCond PosCond;
ImGuiCond SizeCond; ImGuiCond SizeCond;
ImGuiCond ContentSizeCond;
ImGuiCond CollapsedCond; ImGuiCond CollapsedCond;
ImGuiCond SizeConstraintCond;
ImGuiCond FocusCond;
ImGuiCond BgAlphaCond;
ImGuiCond ViewportCond;
ImGuiCond DockCond; ImGuiCond DockCond;
ImVec2 PosVal; ImVec2 PosVal;
ImVec2 PosPivotVal; ImVec2 PosPivotVal;
@ -818,27 +834,28 @@ struct ImGuiNextWindowData
ImGuiID ViewportId; ImGuiID ViewportId;
ImGuiID DockId; ImGuiID DockId;
ImGuiWindowClass WindowClass; ImGuiWindowClass WindowClass;
ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it.
ImGuiNextWindowData() ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
{ inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0; };
PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f);
ContentSizeVal = ImVec2(0.0f, 0.0f);
PosUndock = CollapsedVal = false;
SizeConstraintRect = ImRect();
SizeCallback = NULL;
SizeCallbackUserData = NULL;
BgAlphaVal = FLT_MAX;
ViewportId = DockId = 0;
MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
}
void Clear() enum ImGuiNextItemDataFlags_
{ {
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0; ImGuiNextItemDataFlags_None = 0,
WindowClass = ImGuiWindowClass(); ImGuiNextItemDataFlags_HasWidth = 1 << 0,
} ImGuiNextItemDataFlags_HasOpen = 1 << 1
};
struct ImGuiNextItemData
{
ImGuiNextItemDataFlags Flags;
float Width; // Set by SetNextItemWidth().
bool OpenVal; // Set by SetNextItemOpen() function.
ImGuiCond OpenCond;
ImGuiNextItemData() { memset(this, 0, sizeof(*this)); }
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; }
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -951,12 +968,13 @@ struct ImGuiContext
float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
ImDrawListSharedData DrawListSharedData; ImDrawListSharedData DrawListSharedData;
double Time; double Time;
int FrameCount; int FrameCount;
int FrameCountEnded; int FrameCountEnded;
int FrameCountPlatformEnded; int FrameCountPlatformEnded;
int FrameCountRendered; int FrameCountRendered;
// Windows state
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front
ImVector<ImGuiWindow*> WindowsSortBuffer; ImVector<ImGuiWindow*> WindowsSortBuffer;
@ -967,39 +985,45 @@ struct ImGuiContext
ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
// Item/widgets state and tracking information
ImGuiID HoveredId; // Hovered widget ImGuiID HoveredId; // Hovered widget
bool HoveredIdAllowOverlap; bool HoveredIdAllowOverlap;
ImGuiID HoveredIdPreviousFrame; ImGuiID HoveredIdPreviousFrame;
float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
ImGuiID ActiveId; // Active widget ImGuiID ActiveId; // Active widget
ImGuiID ActiveIdPreviousFrame;
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
float ActiveIdTimer; float ActiveIdTimer;
bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdIsJustActivated; // Set at the time of activation for one frame
bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)
bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state. bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state.
bool ActiveIdPreviousFrameIsAlive; bool ActiveIdHasBeenEditedThisFrame;
bool ActiveIdPreviousFrameHasBeenEdited;
int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
int ActiveIdBlockNavInputFlags; int ActiveIdBlockNavInputFlags;
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
ImGuiWindow* ActiveIdWindow; ImGuiWindow* ActiveIdWindow;
ImGuiWindow* ActiveIdPreviousFrameWindow;
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
ImGuiID ActiveIdPreviousFrame;
bool ActiveIdPreviousFrameIsAlive;
bool ActiveIdPreviousFrameHasBeenEditedBefore;
ImGuiWindow* ActiveIdPreviousFrameWindow;
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
ImVec2 LastValidMousePos;
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. // Next window/item data
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions
// Shared stacks
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont() ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent) ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent)
ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
ImGuiCond NextTreeNodeOpenCond;
// Viewports // Viewports
ImVector<ImGuiViewportP*> Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData. ImVector<ImGuiViewportP*> Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData.
@ -1087,6 +1111,7 @@ struct ImGuiContext
ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer; ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer;
// Widget state // Widget state
ImVec2 LastValidMousePos;
ImGuiInputTextState InputTextState; ImGuiInputTextState InputTextState;
ImFont InputTextPasswordFont; ImFont InputTextPasswordFont;
ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
@ -1148,40 +1173,42 @@ struct ImGuiContext
FontSize = FontBaseSize = 0.0f; FontSize = FontBaseSize = 0.0f;
FontAtlasOwnedByContext = shared_font_atlas ? false : true; FontAtlasOwnedByContext = shared_font_atlas ? false : true;
IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
Time = 0.0f; Time = 0.0f;
FrameCount = 0; FrameCount = 0;
FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1; FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1;
WindowsActiveCount = 0; WindowsActiveCount = 0;
CurrentWindow = NULL; CurrentWindow = NULL;
HoveredWindow = NULL; HoveredWindow = NULL;
HoveredRootWindow = NULL; HoveredRootWindow = NULL;
HoveredWindowUnderMovingWindow = NULL; HoveredWindowUnderMovingWindow = NULL;
MovingWindow = NULL;
HoveredId = 0; HoveredId = 0;
HoveredIdAllowOverlap = false; HoveredIdAllowOverlap = false;
HoveredIdPreviousFrame = 0; HoveredIdPreviousFrame = 0;
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
ActiveId = 0; ActiveId = 0;
ActiveIdPreviousFrame = 0;
ActiveIdIsAlive = 0; ActiveIdIsAlive = 0;
ActiveIdTimer = 0.0f; ActiveIdTimer = 0.0f;
ActiveIdIsJustActivated = false; ActiveIdIsJustActivated = false;
ActiveIdAllowOverlap = false; ActiveIdAllowOverlap = false;
ActiveIdHasBeenPressed = false; ActiveIdHasBeenPressedBefore = false;
ActiveIdHasBeenEdited = false; ActiveIdHasBeenEditedBefore = false;
ActiveIdPreviousFrameIsAlive = false; ActiveIdHasBeenEditedThisFrame = false;
ActiveIdPreviousFrameHasBeenEdited = false;
ActiveIdAllowNavDirFlags = 0x00; ActiveIdAllowNavDirFlags = 0x00;
ActiveIdBlockNavInputFlags = 0x00; ActiveIdBlockNavInputFlags = 0x00;
ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdClickOffset = ImVec2(-1,-1);
ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; ActiveIdWindow = NULL;
ActiveIdSource = ImGuiInputSource_None; ActiveIdSource = ImGuiInputSource_None;
ActiveIdPreviousFrame = 0;
ActiveIdPreviousFrameIsAlive = false;
ActiveIdPreviousFrameHasBeenEditedBefore = false;
ActiveIdPreviousFrameWindow = NULL;
LastActiveId = 0; LastActiveId = 0;
LastActiveIdTimer = 0.0f; LastActiveIdTimer = 0.0f;
LastValidMousePos = ImVec2(0.0f, 0.0f);
MovingWindow = NULL;
NextTreeNodeOpenVal = false;
NextTreeNodeOpenCond = 0;
CurrentViewport = NULL; CurrentViewport = NULL;
MouseViewport = MouseLastHoveredViewport = NULL; MouseViewport = MouseLastHoveredViewport = NULL;
@ -1234,6 +1261,7 @@ struct ImGuiContext
CurrentTabBar = NULL; CurrentTabBar = NULL;
LastValidMousePos = ImVec2(0.0f, 0.0f);
TempInputTextId = 0; TempInputTextId = 0;
ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
DragCurrentAccumDirty = false; DragCurrentAccumDirty = false;
@ -1280,9 +1308,9 @@ struct IMGUI_API ImGuiWindowTempData
ImVec2 CursorPosPrevLine; ImVec2 CursorPosPrevLine;
ImVec2 CursorStartPos; // Initial position in client area with padding ImVec2 CursorStartPos; // Initial position in client area with padding
ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame
ImVec2 CurrentLineSize; ImVec2 CurrLineSize;
float CurrentLineTextBaseOffset;
ImVec2 PrevLineSize; ImVec2 PrevLineSize;
float CurrLineTextBaseOffset;
float PrevLineTextBaseOffset; float PrevLineTextBaseOffset;
int TreeDepth; int TreeDepth;
ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
@ -1308,7 +1336,6 @@ struct IMGUI_API ImGuiWindowTempData
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default]
float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
float NextItemWidth;
float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f]
ImVector<ImGuiItemFlags>ItemFlagsStack; ImVector<ImGuiItemFlags>ItemFlagsStack;
ImVector<float> ItemWidthStack; ImVector<float> ItemWidthStack;
@ -1324,8 +1351,8 @@ struct IMGUI_API ImGuiWindowTempData
ImGuiWindowTempData() ImGuiWindowTempData()
{ {
CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f);
CurrentLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f);
CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
TreeDepth = 0; TreeDepth = 0;
TreeStoreMayJumpToParentOnPop = 0x00; TreeStoreMayJumpToParentOnPop = 0x00;
LastItemId = 0; LastItemId = 0;
@ -1344,7 +1371,6 @@ struct IMGUI_API ImGuiWindowTempData
ItemFlags = ImGuiItemFlags_Default_; ItemFlags = ImGuiItemFlags_Default_;
ItemWidth = 0.0f; ItemWidth = 0.0f;
NextItemWidth = +FLT_MAX;
TextWrapPos = -1.0f; TextWrapPos = -1.0f;
memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
@ -1636,7 +1662,6 @@ namespace ImGui
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
IMGUI_API float GetNextItemWidth();
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
IMGUI_API void PushMultiItemsWidths(int components, float width_full); IMGUI_API void PushMultiItemsWidths(int components, float width_full);
@ -1783,7 +1808,7 @@ namespace ImGui
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging
IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API void TreePushOverrideID(ImGuiID id);
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // Template functions are instantiated in imgui_widgets.cpp for a finite number of types.

View File

@ -139,7 +139,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
if (text_end == NULL) if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT text_end = text + strlen(text); // FIXME-OPT
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset); const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const float wrap_pos_x = window->DC.TextWrapPos; const float wrap_pos_x = window->DC.TextWrapPos;
const bool wrap_enabled = (wrap_pos_x >= 0.0f); const bool wrap_enabled = (wrap_pos_x >= 0.0f);
if (text_end - text > 2000 && !wrap_enabled) if (text_end - text > 2000 && !wrap_enabled)
@ -320,7 +320,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const float w = GetNextItemWidth(); const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2)); const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
@ -358,8 +358,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
const char* text_begin = g.TempBuffer; const char* text_begin = g.TempBuffer;
const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it const float text_base_offset_y = ImMax(0.0f, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
ItemSize(bb); ItemSize(bb);
if (!ItemAdd(bb, 0)) if (!ItemAdd(bb, 0))
@ -564,7 +564,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
if (pressed) if (pressed)
g.ActiveIdHasBeenPressed = true; g.ActiveIdHasBeenPressedBefore = true;
if (g.ActiveIdSource == ImGuiInputSource_Mouse) if (g.ActiveIdSource == ImGuiInputSource_Mouse)
{ {
if (g.ActiveIdIsJustActivated) if (g.ActiveIdIsJustActivated)
@ -612,8 +612,8 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect bb(pos, pos + size); const ImRect bb(pos, pos + size);
@ -1122,7 +1122,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), g.FontSize + style.FramePadding.y*2.0f); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f);
ImRect bb(pos, pos + size); ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y); ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, 0)) if (!ItemAdd(bb, 0))
@ -1156,7 +1156,7 @@ void ImGui::Bullet()
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
ItemSize(bb); ItemSize(bb);
if (!ItemAdd(bb, 0)) if (!ItemAdd(bb, 0))
@ -1210,7 +1210,7 @@ void ImGui::NewLine()
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.LayoutType = ImGuiLayoutType_Vertical;
if (window->DC.CurrentLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
ItemSize(ImVec2(0,0)); ItemSize(ImVec2(0,0));
else else
ItemSize(ImVec2(0.0f, g.FontSize)); ItemSize(ImVec2(0.0f, g.FontSize));
@ -1224,8 +1224,8 @@ void ImGui::AlignTextToFramePadding()
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
window->DC.CurrentLineSize.y = ImMax(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2);
window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y);
} }
// Horizontal/vertical separating line // Horizontal/vertical separating line
@ -1244,7 +1244,7 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
{ {
// 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). Not exposed because it is misleading and it doesn't have an effect on regular layout.
float y1 = window->DC.CursorPos.y; float y1 = window->DC.CursorPos.y;
float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.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_draw, y2));
ItemSize(ImVec2(thickness_layout, 0.0f)); ItemSize(ImVec2(thickness_layout, 0.0f));
if (!ItemAdd(bb, 0)) if (!ItemAdd(bb, 0))
@ -1381,8 +1381,8 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
{ {
// Always consume the SetNextWindowSizeConstraint() call in our early return paths // Always consume the SetNextWindowSizeConstraint() call in our early return paths
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond; bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0;
g.NextWindowData.SizeConstraintCond = 0; g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
@ -1395,7 +1395,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const float expected_w = GetNextItemWidth(); const float expected_w = CalcItemWidth();
const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w; const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w;
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@ -1434,9 +1434,9 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
if (!popup_open) if (!popup_open)
return false; return false;
if (backup_next_window_size_constraint) if (has_window_size_constraint)
{ {
g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
} }
else else
@ -1526,7 +1526,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
items_getter(data, *current_item, &preview_value); items_getter(data, *current_item, &preview_value);
// The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here.
if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond) if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))
SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) if (!BeginCombo(label, preview_value, ImGuiComboFlags_None))
@ -2022,8 +2022,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const float w = GetNextItemWidth(); const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@ -2095,7 +2094,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int
bool value_changed = false; bool value_changed = false;
BeginGroup(); BeginGroup();
PushID(label); PushID(label);
PushMultiItemsWidths(components, GetNextItemWidth()); PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size; size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
@ -2142,7 +2141,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
PushID(label); PushID(label);
BeginGroup(); BeginGroup();
PushMultiItemsWidths(2, GetNextItemWidth()); PushMultiItemsWidths(2, CalcItemWidth());
bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power);
PopItemWidth(); PopItemWidth();
@ -2187,7 +2186,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
PushID(label); PushID(label);
BeginGroup(); BeginGroup();
PushMultiItemsWidths(2, GetNextItemWidth()); PushMultiItemsWidths(2, CalcItemWidth());
bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format);
PopItemWidth(); PopItemWidth();
@ -2465,7 +2464,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const float w = GetNextItemWidth(); const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
@ -2543,7 +2542,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
bool value_changed = false; bool value_changed = false;
BeginGroup(); BeginGroup();
PushID(label); PushID(label);
PushMultiItemsWidths(components, GetNextItemWidth()); PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size; size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
@ -2792,7 +2791,8 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
ImStrTrimBlanks(data_buf); ImStrTrimBlanks(data_buf);
g.CurrentWindow->DC.CursorPos = bb.Min; g.CurrentWindow->DC.CursorPos = bb.Min;
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited;
flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
if (init) if (init)
{ {
@ -2801,7 +2801,11 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
g.TempInputTextId = g.ActiveId; g.TempInputTextId = g.ActiveId;
} }
if (value_changed) if (value_changed)
return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL); {
value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
if (value_changed)
MarkItemEdited(id);
}
return false; return false;
} }
@ -2824,6 +2828,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
flags |= ImGuiInputTextFlags_CharsDecimal; flags |= ImGuiInputTextFlags_CharsDecimal;
flags |= ImGuiInputTextFlags_AutoSelectAll; flags |= ImGuiInputTextFlags_AutoSelectAll;
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselve by comparing the actual data rather than the string.
if (step != NULL) if (step != NULL)
{ {
@ -2831,7 +2836,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
PushID(label); PushID(label);
SetNextItemWidth(ImMax(1.0f, GetNextItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
@ -2865,6 +2870,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
} }
if (value_changed)
MarkItemEdited(window->DC.LastItemId);
return value_changed; return value_changed;
} }
@ -2879,7 +2886,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
bool value_changed = false; bool value_changed = false;
BeginGroup(); BeginGroup();
PushID(label); PushID(label);
PushMultiItemsWidths(components, GetNextItemWidth()); PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size; size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
@ -3329,7 +3336,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
BeginGroup(); BeginGroup();
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);
ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
@ -4047,7 +4054,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (label_size.x > 0) if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
if (value_changed) if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
MarkItemEdited(id); MarkItemEdited(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
@ -4090,8 +4097,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const float square_sz = GetFrameHeight(); const float square_sz = GetFrameHeight();
const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
const float w_items_all = GetNextItemWidth() - w_extra; const float w_items_all = CalcItemWidth() - w_extra;
const char* label_display_end = FindRenderedTextEnd(label); const char* label_display_end = FindRenderedTextEnd(label);
g.NextItemData.ClearFlags();
BeginGroup(); BeginGroup();
PushID(label); PushID(label);
@ -4371,6 +4379,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImGuiStyle& style = g.Style; ImGuiStyle& style = g.Style;
ImGuiIO& io = g.IO; ImGuiIO& io = g.IO;
const float width = CalcItemWidth();
g.NextItemData.ClearFlags();
PushID(label); PushID(label);
BeginGroup(); BeginGroup();
@ -4397,7 +4408,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImVec2 picker_pos = window->DC.CursorPos; ImVec2 picker_pos = window->DC.CursorPos;
float square_sz = GetFrameHeight(); float square_sz = GetFrameHeight();
float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
float sv_picker_size = ImMax(bars_width * 1, GetNextItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f); float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
@ -4940,7 +4951,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreePop() // - TreePop()
// - TreeAdvanceToLabelPos() // - TreeAdvanceToLabelPos()
// - GetTreeNodeToLabelSpacing() // - GetTreeNodeToLabelSpacing()
// - SetNextTreeNodeOpen() // - SetNextItemOpen()
// - CollapsingHeader() // - CollapsingHeader()
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -5034,17 +5045,17 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
if (flags & ImGuiTreeNodeFlags_Leaf) if (flags & ImGuiTreeNodeFlags_Leaf)
return true; return true;
// We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImGuiStorage* storage = window->DC.StateStorage; ImGuiStorage* storage = window->DC.StateStorage;
bool is_open; bool is_open;
if (g.NextTreeNodeOpenCond != 0) if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen)
{ {
if (g.NextTreeNodeOpenCond & ImGuiCond_Always) if (g.NextItemData.OpenCond & ImGuiCond_Always)
{ {
is_open = g.NextTreeNodeOpenVal; is_open = g.NextItemData.OpenVal;
storage->SetInt(id, is_open); storage->SetInt(id, is_open);
} }
else else
@ -5053,7 +5064,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
const int stored_value = storage->GetInt(id, -1); const int stored_value = storage->GetInt(id, -1);
if (stored_value == -1) if (stored_value == -1)
{ {
is_open = g.NextTreeNodeOpenVal; is_open = g.NextItemData.OpenVal;
storage->SetInt(id, is_open); storage->SetInt(id, is_open);
} }
else else
@ -5061,7 +5072,6 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
is_open = stored_value != 0; is_open = stored_value != 0;
} }
} }
g.NextTreeNodeOpenCond = 0;
} }
else else
{ {
@ -5092,8 +5102,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
const ImVec2 label_size = CalcTextSize(label, label_end, false); const ImVec2 label_size = CalcTextSize(label, label_end, false);
// We vertically grow up to current line height up the typical widget height. // We vertically grow up to current line height up the typical widget height.
const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
const float frame_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetWorkRectMax().x, window->DC.CursorPos.y + frame_height)); ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetWorkRectMax().x, window->DC.CursorPos.y + frame_height));
if (display_frame) if (display_frame)
{ {
@ -5290,13 +5300,15 @@ float ImGui::GetTreeNodeToLabelSpacing()
return g.FontSize + (g.Style.FramePadding.x * 2.0f); return g.FontSize + (g.Style.FramePadding.x * 2.0f);
} }
void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond) // Set next TreeNode/CollapsingHeader open state.
void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.CurrentWindow->SkipItems) if (g.CurrentWindow->SkipItems)
return; return;
g.NextTreeNodeOpenVal = is_open; g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen;
g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always; g.NextItemData.OpenVal = is_open;
g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always;
} }
// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
@ -5360,7 +5372,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrentLineTextBaseOffset; pos.y += window->DC.CurrLineTextBaseOffset;
ImRect bb_inner(pos, pos + size); ImRect bb_inner(pos, pos + size);
ItemSize(size); ItemSize(size);
@ -5486,20 +5498,22 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags
// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty"
bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
{ {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
return false; return false;
const ImGuiStyle& style = GetStyle(); const ImGuiStyle& style = g.Style;
const ImGuiID id = GetID(label); const ImGuiID id = GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
// Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
g.NextItemData.ClearFlags();
if (!IsRectVisible(bb.Min, bb.Max)) if (!IsRectVisible(bb.Min, bb.Max))
{ {
@ -5612,7 +5626,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (frame_size.x == 0.0f) if (frame_size.x == 0.0f)
frame_size.x = GetNextItemWidth(); frame_size.x = CalcItemWidth();
if (frame_size.y == 0.0f) if (frame_size.y == 0.0f)
frame_size.y = label_size.y + (style.FramePadding.y * 2); frame_size.y = label_size.y + (style.FramePadding.y * 2);
@ -5939,7 +5953,7 @@ void ImGui::EndMenuBar()
PopClipRect(); PopClipRect();
PopID(); PopID();
window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.
window->DC.GroupStack.back().AdvanceCursor = false; window->DC.GroupStack.back().EmitItem = false;
EndGroup(); // Restore position on layer 0 EndGroup(); // Restore position on layer 0
window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayerCurrent = ImGuiNavLayer_Main;

View File

@ -120,6 +120,7 @@ struct FreeTypeTest
WantRebuild |= ImGui::CheckboxFlags("MonoHinting", &FontsFlags, ImGuiFreeType::MonoHinting); WantRebuild |= ImGui::CheckboxFlags("MonoHinting", &FontsFlags, ImGuiFreeType::MonoHinting);
WantRebuild |= ImGui::CheckboxFlags("Bold", &FontsFlags, ImGuiFreeType::Bold); WantRebuild |= ImGui::CheckboxFlags("Bold", &FontsFlags, ImGuiFreeType::Bold);
WantRebuild |= ImGui::CheckboxFlags("Oblique", &FontsFlags, ImGuiFreeType::Oblique); WantRebuild |= ImGui::CheckboxFlags("Oblique", &FontsFlags, ImGuiFreeType::Oblique);
WantRebuild |= ImGui::CheckboxFlags("Monochrome", &FontsFlags, ImGuiFreeType::Monochrome);
} }
ImGui::End(); ImGui::End();
} }

View File

@ -12,6 +12,7 @@
// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX. // - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. // - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
// - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions(). // - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
// - v0.62: (2019/02/09) added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!)
// Gamma Correct Blending: // Gamma Correct Blending:
// FreeType assumes blending in linear space rather than gamma space. // FreeType assumes blending in linear space rather than gamma space.
@ -109,6 +110,7 @@ namespace
FT_Face Face; FT_Face Face;
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
FT_Int32 LoadFlags; FT_Int32 LoadFlags;
FT_Render_Mode RenderMode;
}; };
// From SDL_ttf: Handy routines for converting from fixed point // From SDL_ttf: Handy routines for converting from fixed point
@ -142,6 +144,11 @@ namespace
else else
LoadFlags |= FT_LOAD_TARGET_NORMAL; LoadFlags |= FT_LOAD_TARGET_NORMAL;
if (UserFlags & ImGuiFreeType::Monochrome)
RenderMode = FT_RENDER_MODE_MONO;
else
RenderMode = FT_RENDER_MODE_NORMAL;
return true; return true;
} }
@ -208,7 +215,7 @@ namespace
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
{ {
FT_GlyphSlot slot = Face->glyph; FT_GlyphSlot slot = Face->glyph;
FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); FT_Error error = FT_Render_Glyph(slot, RenderMode);
if (error != 0) if (error != 0)
return NULL; return NULL;
@ -230,6 +237,10 @@ namespace
const uint8_t* src = ft_bitmap->buffer; const uint8_t* src = ft_bitmap->buffer;
const uint32_t src_pitch = ft_bitmap->pitch; const uint32_t src_pitch = ft_bitmap->pitch;
switch (ft_bitmap->pixel_mode)
{
case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.
{
if (multiply_table == NULL) if (multiply_table == NULL)
{ {
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
@ -241,6 +252,28 @@ namespace
for (uint32_t x = 0; x < w; x++) for (uint32_t x = 0; x < w; x++)
dst[x] = multiply_table[src[x]]; dst[x] = multiply_table[src[x]];
} }
break;
}
case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.
{
uint8_t color0 = multiply_table ? multiply_table[0] : 0;
uint8_t color1 = multiply_table ? multiply_table[255] : 255;
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
{
uint8_t bits = 0;
const uint8_t* bits_ptr = src;
for (uint32_t x = 0; x < w; x++, bits <<= 1)
{
if ((x & 7) == 0)
bits = *bits_ptr++;
dst[x] = (bits & 0x80) ? color1 : color0;
}
}
break;
}
default:
IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
}
} }
} }

View File

@ -24,7 +24,8 @@ namespace ImGuiFreeType
LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
Bold = 1 << 5, // Styling: Should we artificially embolden the font? Bold = 1 << 5, // Styling: Should we artificially embolden the font?
Oblique = 1 << 6 // Styling: Should we slant the font, emulating italic style? Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style?
Monochrome = 1 << 7 // Disable anti-aliasing. Combine this with MonoHinting for best results!
}; };
IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0);