|
@@ -276,9 +276,9 @@ void ImGui::TextV(const char* fmt, va_list args)
|
|
return;
|
|
return;
|
|
|
|
|
|
// FIXME-OPT: Handle the %s shortcut?
|
|
// FIXME-OPT: Handle the %s shortcut?
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
- const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
- TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
|
|
|
|
|
|
+ const char* text, *text_end;
|
|
|
|
+ ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
|
|
|
|
+ TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
|
|
}
|
|
}
|
|
|
|
|
|
void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
|
|
void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
|
|
@@ -359,8 +359,8 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
|
|
const ImGuiStyle& style = g.Style;
|
|
const ImGuiStyle& style = g.Style;
|
|
const float w = CalcItemWidth();
|
|
const float w = CalcItemWidth();
|
|
|
|
|
|
- const char* value_text_begin = &g.TempBuffer[0];
|
|
|
|
- const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
|
|
+ const char* value_text_begin, *value_text_end;
|
|
|
|
+ ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args);
|
|
const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false);
|
|
const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false);
|
|
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
|
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
|
|
|
|
|
@@ -395,8 +395,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
const ImGuiStyle& style = g.Style;
|
|
const ImGuiStyle& style = g.Style;
|
|
|
|
|
|
- const char* text_begin = g.TempBuffer;
|
|
|
|
- const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
|
|
+ const char* text_begin, *text_end;
|
|
|
|
+ ImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args);
|
|
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
|
|
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
|
|
const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding
|
|
const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding
|
|
ImVec2 pos = window->DC.CursorPos;
|
|
ImVec2 pos = window->DC.CursorPos;
|
|
@@ -1918,9 +1918,9 @@ static const char* PatchFormatStringFloatToInt(const char* fmt)
|
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
|
if (fmt_start == fmt && fmt_end[0] == 0)
|
|
if (fmt_start == fmt && fmt_end[0] == 0)
|
|
return "%d";
|
|
return "%d";
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
- ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision.
|
|
|
|
- return g.TempBuffer;
|
|
|
|
|
|
+ const char* tmp_format;
|
|
|
|
+ ImFormatStringToTempBuffer(&tmp_format, NULL, "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision.
|
|
|
|
+ return tmp_format;
|
|
#else
|
|
#else
|
|
IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d"
|
|
IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d"
|
|
#endif
|
|
#endif
|
|
@@ -3579,6 +3579,7 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f
|
|
// - InputTextReindexLines() [Internal]
|
|
// - InputTextReindexLines() [Internal]
|
|
// - InputTextReindexLinesRange() [Internal]
|
|
// - InputTextReindexLinesRange() [Internal]
|
|
// - InputTextEx() [Internal]
|
|
// - InputTextEx() [Internal]
|
|
|
|
+// - DebugNodeInputTextState() [Internal]
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
|
bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
|
@@ -3936,6 +3937,41 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Find the shortest single replacement we can make to get the new text from the old text.
|
|
|
|
+// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end.
|
|
|
|
+// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly.
|
|
|
|
+static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a)
|
|
|
|
+{
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
|
+ const ImWchar* old_buf = state->TextW.Data;
|
|
|
|
+ const int old_length = state->CurLenW;
|
|
|
|
+ const int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a);
|
|
|
|
+ g.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar));
|
|
|
|
+ ImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data;
|
|
|
|
+ ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a);
|
|
|
|
+
|
|
|
|
+ const int shorter_length = ImMin(old_length, new_length);
|
|
|
|
+ int first_diff;
|
|
|
|
+ for (first_diff = 0; first_diff < shorter_length; first_diff++)
|
|
|
|
+ if (old_buf[first_diff] != new_buf[first_diff])
|
|
|
|
+ break;
|
|
|
|
+ if (first_diff == old_length && first_diff == new_length)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ int old_last_diff = old_length - 1;
|
|
|
|
+ int new_last_diff = new_length - 1;
|
|
|
|
+ for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--)
|
|
|
|
+ if (old_buf[old_last_diff] != new_buf[new_last_diff])
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ const int insert_len = new_last_diff - first_diff + 1;
|
|
|
|
+ const int delete_len = old_last_diff - first_diff + 1;
|
|
|
|
+ if (insert_len > 0 || delete_len > 0)
|
|
|
|
+ if (STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len))
|
|
|
|
+ for (int i = 0; i < delete_len; i++)
|
|
|
|
+ p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i);
|
|
|
|
+}
|
|
|
|
+
|
|
// Edit a string of text
|
|
// Edit a string of text
|
|
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
|
|
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
|
|
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
|
|
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
|
|
@@ -4056,17 +4092,21 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
|
state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
|
memcpy(state->InitialTextA.Data, buf, buf_len + 1);
|
|
memcpy(state->InitialTextA.Data, buf, buf_len + 1);
|
|
|
|
|
|
|
|
+ // Preserve cursor position and undo/redo stack if we come back to same widget
|
|
|
|
+ // FIXME: Since we reworked this on 2022/06, may want to differenciate recycle_cursor vs recycle_undostate?
|
|
|
|
+ bool recycle_state = (state->ID == id && !init_changed_specs);
|
|
|
|
+ if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0)))
|
|
|
|
+ recycle_state = false;
|
|
|
|
+
|
|
// Start edition
|
|
// Start edition
|
|
const char* buf_end = NULL;
|
|
const char* buf_end = NULL;
|
|
|
|
+ state->ID = id;
|
|
state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
|
state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.
|
|
state->TextA.resize(0);
|
|
state->TextA.resize(0);
|
|
state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then)
|
|
state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then)
|
|
state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
|
|
state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
|
|
state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
|
|
state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
|
|
|
|
|
|
- // Preserve cursor position and undo/redo stack if we come back to same widget
|
|
|
|
- // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed.
|
|
|
|
- const bool recycle_state = (state->ID == id && !init_changed_specs);
|
|
|
|
if (recycle_state)
|
|
if (recycle_state)
|
|
{
|
|
{
|
|
// Recycle existing cursor/selection/undo stack but clamp position
|
|
// Recycle existing cursor/selection/undo stack but clamp position
|
|
@@ -4075,7 +4115,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- state->ID = id;
|
|
|
|
state->ScrollX = 0.0f;
|
|
state->ScrollX = 0.0f;
|
|
stb_textedit_initialize_state(&state->Stb, !is_multiline);
|
|
stb_textedit_initialize_state(&state->Stb, !is_multiline);
|
|
}
|
|
}
|
|
@@ -4520,8 +4559,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
if (buf_dirty)
|
|
if (buf_dirty)
|
|
{
|
|
{
|
|
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
|
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
|
|
|
+ InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?
|
|
if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
|
|
if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
|
|
- state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
|
|
|
|
|
|
+ state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize
|
|
state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
|
|
state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
|
|
state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
|
state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
|
|
state->CursorAnimReset();
|
|
state->CursorAnimReset();
|
|
@@ -4825,6 +4865,40 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
return value_changed;
|
|
return value_changed;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
|
|
|
|
+{
|
|
|
|
+#ifndef IMGUI_DISABLE_METRICS_WINDOW
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
|
+ ImStb::STB_TexteditState* stb_state = &state->Stb;
|
|
|
|
+ ImStb::StbUndoState* undo_state = &stb_state->undostate;
|
|
|
|
+ Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId);
|
|
|
|
+ Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, state->CurLenW, stb_state->cursor, stb_state->select_start, stb_state->select_end);
|
|
|
|
+ Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point);
|
|
|
|
+ if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state
|
|
|
|
+ {
|
|
|
|
+ PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
|
|
|
+ for (int n = 0; n < STB_TEXTEDIT_UNDOSTATECOUNT; n++)
|
|
|
|
+ {
|
|
|
|
+ ImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n];
|
|
|
|
+ const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' ';
|
|
|
|
+ if (undo_rec_type == ' ')
|
|
|
|
+ BeginDisabled();
|
|
|
|
+ char buf[64] = "";
|
|
|
|
+ if (undo_rec_type != ' ' && undo_rec->char_storage != -1)
|
|
|
|
+ ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length);
|
|
|
|
+ Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"",
|
|
|
|
+ undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf);
|
|
|
|
+ if (undo_rec_type == ' ')
|
|
|
|
+ EndDisabled();
|
|
|
|
+ }
|
|
|
|
+ PopStyleVar();
|
|
|
|
+ }
|
|
|
|
+ EndChild();
|
|
|
|
+#else
|
|
|
|
+ IM_UNUSED(state);
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc.
|
|
// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc.
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
@@ -5806,9 +5880,9 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char
|
|
if (window->SkipItems)
|
|
if (window->SkipItems)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
- const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
- return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
|
|
|
|
|
|
+ const char* label, *label_end;
|
|
|
|
+ ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
|
|
|
|
+ return TreeNodeBehavior(window->GetID(str_id), flags, label, label_end);
|
|
}
|
|
}
|
|
|
|
|
|
bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
|
|
bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
|
|
@@ -5817,9 +5891,9 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char
|
|
if (window->SkipItems)
|
|
if (window->SkipItems)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
- const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
- return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
|
|
|
|
|
|
+ const char* label, *label_end;
|
|
|
|
+ ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
|
|
|
|
+ return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end);
|
|
}
|
|
}
|
|
|
|
|
|
bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
|
bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
|
@@ -6878,14 +6952,19 @@ static bool IsRootOfOpenMenuSet()
|
|
if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu))
|
|
if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
- // Initially we used 'OpenParentId' to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) based on parent ID.
|
|
|
|
|
|
+ // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others
|
|
|
|
+ // (e.g. inside menu bar vs loose menu items) based on parent ID.
|
|
// This would however prevent the use of e.g. PuhsID() user code submitting menus.
|
|
// This would however prevent the use of e.g. PuhsID() user code submitting menus.
|
|
// Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag,
|
|
// Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag,
|
|
// making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.
|
|
// making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.
|
|
// Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup
|
|
// Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup
|
|
- // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first chilld menu.
|
|
|
|
|
|
+ // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu.
|
|
|
|
+ // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer.
|
|
|
|
+ // This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still
|
|
|
|
+ // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart
|
|
|
|
+ // it likely won't be a problem anyone runs into.
|
|
const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
- return (/*upper_popup->OpenParentId == window->IDStack.back() &&*/ upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu));
|
|
|
|
|
|
+ return (window->DC.NavLayerCurrent == upper_popup->ParentNavLayer && upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu));
|
|
}
|
|
}
|
|
|
|
|
|
bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
|
bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
|
@@ -6900,7 +6979,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
|
bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);
|
|
bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);
|
|
|
|
|
|
// Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)
|
|
// Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)
|
|
- // The first menu in a hierarchy isn't so hovering doesn't get accross (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation.
|
|
|
|
|
|
+ // The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation.
|
|
ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
|
|
ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
|
|
if (window->Flags & ImGuiWindowFlags_ChildMenu)
|
|
if (window->Flags & ImGuiWindowFlags_ChildMenu)
|
|
flags |= ImGuiWindowFlags_ChildWindow;
|
|
flags |= ImGuiWindowFlags_ChildWindow;
|