|
|
@@ -1,4 +1,4 @@
|
|
|
-// dear imgui, v1.84
|
|
|
+// dear imgui, v1.85 WIP
|
|
|
// (widgets code)
|
|
|
|
|
|
/*
|
|
|
@@ -152,9 +152,13 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
if (window->SkipItems)
|
|
|
return;
|
|
|
-
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- IM_ASSERT(text != NULL);
|
|
|
+
|
|
|
+ // Accept null ranges
|
|
|
+ if (text == text_end)
|
|
|
+ text = text_end = "";
|
|
|
+
|
|
|
+ // Calculate length
|
|
|
const char* text_begin = text;
|
|
|
if (text_end == NULL)
|
|
|
text_end = text + strlen(text); // FIXME-OPT
|
|
|
@@ -269,6 +273,7 @@ void ImGui::TextV(const char* fmt, va_list args)
|
|
|
if (window->SkipItems)
|
|
|
return;
|
|
|
|
|
|
+ // 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);
|
|
|
@@ -566,6 +571,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
|
|
ClearActiveID();
|
|
|
else
|
|
|
SetActiveID(id, window); // Hold on ID
|
|
|
+ if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
|
|
+ SetFocusID(id, window);
|
|
|
g.ActiveIdMouseButton = mouse_button_clicked;
|
|
|
FocusWindow(window);
|
|
|
}
|
|
|
@@ -576,6 +583,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
|
|
const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay;
|
|
|
if (!has_repeated_at_least_once)
|
|
|
pressed = true;
|
|
|
+ if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
|
|
+ SetFocusID(id, window);
|
|
|
ClearActiveID();
|
|
|
}
|
|
|
|
|
|
@@ -600,13 +609,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
|
|
bool nav_activated_by_code = (g.NavActivateId == id);
|
|
|
bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed);
|
|
|
if (nav_activated_by_code || nav_activated_by_inputs)
|
|
|
- pressed = true;
|
|
|
- if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id)
|
|
|
{
|
|
|
// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
|
|
|
- g.NavActivateId = id; // This is so SetActiveId assign a Nav source
|
|
|
+ pressed = true;
|
|
|
SetActiveID(id, window);
|
|
|
- if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus))
|
|
|
+ g.ActiveIdSource = ImGuiInputSource_Nav;
|
|
|
+ if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
|
|
SetFocusID(id, window);
|
|
|
}
|
|
|
}
|
|
|
@@ -1577,7 +1585,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
|
|
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
|
|
|
const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id);
|
|
|
bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None);
|
|
|
- if ((pressed || g.NavActivateId == id) && !popup_open)
|
|
|
+ if (pressed && !popup_open)
|
|
|
{
|
|
|
OpenPopupEx(popup_id, ImGuiPopupFlags_None);
|
|
|
popup_open = true;
|
|
|
@@ -2385,7 +2393,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
|
|
|
|
|
const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
|
|
|
ItemSize(total_bb, style.FramePadding.y);
|
|
|
- if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0))
|
|
|
+ if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
|
|
|
return false;
|
|
|
|
|
|
// Default format string when passing NULL
|
|
|
@@ -2402,21 +2410,23 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
|
|
const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
|
|
|
const bool clicked = (hovered && g.IO.MouseClicked[0]);
|
|
|
const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]);
|
|
|
- if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id)
|
|
|
+ if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id)
|
|
|
{
|
|
|
SetActiveID(id, window);
|
|
|
SetFocusID(id, window);
|
|
|
FocusWindow(window);
|
|
|
g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
|
|
|
- if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id))
|
|
|
- temp_input_is_active = true;
|
|
|
+ if (temp_input_allowed)
|
|
|
+ if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavActivateInputId == id)
|
|
|
+ temp_input_is_active = true;
|
|
|
}
|
|
|
+
|
|
|
// Experimental: simple click (without moving) turns Drag into an InputText
|
|
|
- // FIXME: Currently polling ImGuiConfigFlags_IsTouchScreen, may either poll an hypothetical ImGuiBackendFlags_HasKeyboard and/or an explicit drag settings.
|
|
|
if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active)
|
|
|
if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR))
|
|
|
{
|
|
|
- g.NavInputId = id;
|
|
|
+ g.NavActivateId = g.NavActivateInputId = id;
|
|
|
+ g.NavActivateFlags = ImGuiActivateFlags_PreferInput;
|
|
|
temp_input_is_active = true;
|
|
|
}
|
|
|
}
|
|
|
@@ -3016,7 +3026,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
|
|
|
|
|
const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
|
|
|
ItemSize(total_bb, style.FramePadding.y);
|
|
|
- if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0))
|
|
|
+ if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
|
|
|
return false;
|
|
|
|
|
|
// Default format string when passing NULL
|
|
|
@@ -3032,13 +3042,13 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
|
|
{
|
|
|
const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
|
|
|
const bool clicked = (hovered && g.IO.MouseClicked[0]);
|
|
|
- if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
|
|
|
+ if (focus_requested || clicked || g.NavActivateId == id || g.NavActivateInputId == id)
|
|
|
{
|
|
|
SetActiveID(id, window);
|
|
|
SetFocusID(id, window);
|
|
|
FocusWindow(window);
|
|
|
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
|
|
|
- if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id))
|
|
|
+ if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id))
|
|
|
temp_input_is_active = true;
|
|
|
}
|
|
|
}
|
|
|
@@ -3190,7 +3200,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
|
|
format = PatchFormatStringFloatToInt(format);
|
|
|
|
|
|
const bool hovered = ItemHoverable(frame_bb, id);
|
|
|
- if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id)
|
|
|
+ if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id)
|
|
|
{
|
|
|
SetActiveID(id, window);
|
|
|
SetFocusID(id, window);
|
|
|
@@ -3454,7 +3464,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
|
|
|
style.FramePadding.x = style.FramePadding.y;
|
|
|
ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups;
|
|
|
if (flags & ImGuiInputTextFlags_ReadOnly)
|
|
|
- BeginDisabled(true);
|
|
|
+ BeginDisabled();
|
|
|
SameLine(0, style.ItemInnerSpacing.x);
|
|
|
if (ButtonEx("-", ImVec2(button_size, button_size), button_flags))
|
|
|
{
|
|
|
@@ -3984,13 +3994,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
ImGuiItemStatusFlags item_status_flags = 0;
|
|
|
if (is_multiline)
|
|
|
{
|
|
|
- if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable))
|
|
|
+ ImVec2 backup_pos = window->DC.CursorPos;
|
|
|
+ ItemSize(total_bb, style.FramePadding.y);
|
|
|
+ if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))
|
|
|
{
|
|
|
- ItemSize(total_bb, style.FramePadding.y);
|
|
|
EndGroup();
|
|
|
return false;
|
|
|
}
|
|
|
item_status_flags = g.LastItemData.StatusFlags;
|
|
|
+ window->DC.CursorPos = backup_pos;
|
|
|
|
|
|
// We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.
|
|
|
PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
|
|
|
@@ -4015,7 +4027,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
// Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd)
|
|
|
ItemSize(total_bb, style.FramePadding.y);
|
|
|
if (!(flags & ImGuiInputTextFlags_MergedItem))
|
|
|
- if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable))
|
|
|
+ if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))
|
|
|
return false;
|
|
|
item_status_flags = g.LastItemData.StatusFlags;
|
|
|
}
|
|
|
@@ -4030,7 +4042,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
const bool focus_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
|
|
|
|
|
|
const bool user_clicked = hovered && io.MouseClicked[0];
|
|
|
- const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard));
|
|
|
+ const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavActivateInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard));
|
|
|
const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
|
|
|
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
|
|
|
|
|
|
@@ -4257,6 +4269,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable);
|
|
|
const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable;
|
|
|
|
|
|
+ // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.
|
|
|
+ const bool is_validate = IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter) || IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed) || IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed);
|
|
|
+ const bool is_cancel = IsKeyPressedMap(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed);
|
|
|
+
|
|
|
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
|
|
|
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
|
|
|
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
|
|
|
@@ -4277,7 +4293,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
}
|
|
|
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
|
|
|
}
|
|
|
- else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter))
|
|
|
+ else if (is_validate)
|
|
|
{
|
|
|
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
|
|
|
if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
|
|
|
@@ -4291,7 +4307,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|
|
state->OnKeyPressed((int)c);
|
|
|
}
|
|
|
}
|
|
|
- else if (IsKeyPressedMap(ImGuiKey_Escape))
|
|
|
+ else if (is_cancel)
|
|
|
{
|
|
|
clear_active_id = cancel_edit = true;
|
|
|
}
|
|
|
@@ -5906,12 +5922,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
|
|
toggled = true;
|
|
|
}
|
|
|
|
|
|
- if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
|
|
|
+ if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)
|
|
|
{
|
|
|
toggled = true;
|
|
|
NavMoveRequestCancel();
|
|
|
}
|
|
|
- if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
|
|
|
+ if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
|
|
|
{
|
|
|
toggled = true;
|
|
|
NavMoveRequestCancel();
|
|
|
@@ -6153,20 +6169,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
|
|
|
}
|
|
|
|
|
|
- bool item_add;
|
|
|
const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
|
|
|
- if (disabled_item)
|
|
|
- {
|
|
|
- ImGuiItemFlags backup_item_flags = g.CurrentItemFlags;
|
|
|
- g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
|
|
|
- item_add = ItemAdd(bb, id);
|
|
|
- g.CurrentItemFlags = backup_item_flags;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- item_add = ItemAdd(bb, id);
|
|
|
- }
|
|
|
-
|
|
|
+ const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
|
|
|
if (span_all_columns)
|
|
|
{
|
|
|
window->ClipRect.Min.x = backup_clip_rect_min_x;
|
|
|
@@ -6178,7 +6182,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
|
|
|
const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
|
|
|
if (disabled_item && !disabled_global) // Only testing this as an optimization
|
|
|
- BeginDisabled(true);
|
|
|
+ BeginDisabled();
|
|
|
|
|
|
// FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only,
|
|
|
// which would be advantageous since most selectable are not selected.
|
|
|
@@ -6215,7 +6219,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|
|
{
|
|
|
if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
|
|
|
{
|
|
|
- SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos));
|
|
|
+ SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); // (bb == NavRect)
|
|
|
g.NavDisableHighlight = true;
|
|
|
}
|
|
|
}
|
|
|
@@ -6480,7 +6484,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
|
|
|
float v0 = values_getter(data, (0 + values_offset) % values_count);
|
|
|
float t0 = 0.0f;
|
|
|
ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle
|
|
|
- float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands
|
|
|
+ float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands
|
|
|
|
|
|
const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
|
|
|
const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered);
|
|
|
@@ -6696,21 +6700,21 @@ void ImGui::EndMenuBar()
|
|
|
// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
|
|
|
if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
|
|
{
|
|
|
+ // Try to find out if the request is for one of our child menu
|
|
|
ImGuiWindow* nav_earliest_child = g.NavWindow;
|
|
|
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
|
|
nav_earliest_child = nav_earliest_child->ParentWindow;
|
|
|
- if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None)
|
|
|
+ if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0)
|
|
|
{
|
|
|
// To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
|
|
|
- // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost)
|
|
|
+ // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering)
|
|
|
const ImGuiNavLayer layer = ImGuiNavLayer_Menu;
|
|
|
IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check
|
|
|
FocusWindow(window);
|
|
|
SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
|
|
|
g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
|
|
|
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
|
- g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
|
|
|
- NavMoveRequestCancel();
|
|
|
+ NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags); // Repeat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6799,7 +6803,7 @@ void ImGui::EndMainMenuBar()
|
|
|
End();
|
|
|
}
|
|
|
|
|
|
-bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
+bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
if (window->SkipItems)
|
|
|
@@ -6866,13 +6870,15 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
|
|
|
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.
|
|
|
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
|
|
|
- float icon_w = 0.0f; // FIXME: This not currently exposed for BeginMenu() however you can call window->DC.MenuColumns.DeclColumns(w, 0, 0, 0) yourself
|
|
|
+ float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
|
|
|
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
|
|
|
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
|
|
|
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
|
|
|
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
|
|
|
pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f));
|
|
|
RenderText(text_pos, label);
|
|
|
+ if (icon_w > 0.0f)
|
|
|
+ RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
|
|
|
RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
|
|
|
}
|
|
|
if (!enabled)
|
|
|
@@ -6889,38 +6895,30 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
// Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu
|
|
|
// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
|
|
|
bool moving_toward_other_child_menu = false;
|
|
|
-
|
|
|
ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL;
|
|
|
if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar))
|
|
|
{
|
|
|
- // FIXME-DPI: Values should be derived from a master "scale" factor.
|
|
|
+ float ref_unit = g.FontSize; // FIXME-DPI
|
|
|
ImRect next_window_rect = child_menu_window->Rect();
|
|
|
- ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
|
|
|
+ ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta);
|
|
|
ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
|
|
|
ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
|
|
|
- float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
|
|
|
- ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
|
|
|
- tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
|
|
|
- tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
|
|
|
+ float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack.
|
|
|
+ ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues (FIXME: ??)
|
|
|
+ tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
|
|
|
+ tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f);
|
|
|
moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
|
|
|
- //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]
|
|
|
+ //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_other_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]
|
|
|
}
|
|
|
-
|
|
|
- // FIXME: Hovering a disabled BeginMenu or MenuItem won't close us
|
|
|
if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu)
|
|
|
want_close = true;
|
|
|
|
|
|
- if (!menu_is_open && hovered && pressed) // Click to open
|
|
|
+ // Open
|
|
|
+ if (!menu_is_open && pressed) // Click/activate to open
|
|
|
want_open = true;
|
|
|
else if (!menu_is_open && hovered && !moving_toward_other_child_menu) // Hover to open
|
|
|
want_open = true;
|
|
|
-
|
|
|
- if (g.NavActivateId == id)
|
|
|
- {
|
|
|
- want_close = menu_is_open;
|
|
|
- want_open = !menu_is_open;
|
|
|
- }
|
|
|
- if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
|
|
|
+ if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
|
|
|
{
|
|
|
want_open = true;
|
|
|
NavMoveRequestCancel();
|
|
|
@@ -6938,7 +6936,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
{
|
|
|
want_open = true;
|
|
|
}
|
|
|
- else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
|
|
|
+ else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
|
|
|
{
|
|
|
want_open = true;
|
|
|
NavMoveRequestCancel();
|
|
|
@@ -6977,6 +6975,11 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
return menu_is_open;
|
|
|
}
|
|
|
|
|
|
+bool ImGui::BeginMenu(const char* label, bool enabled)
|
|
|
+{
|
|
|
+ return BeginMenuEx(label, NULL, enabled);
|
|
|
+}
|
|
|
+
|
|
|
void ImGui::EndMenu()
|
|
|
{
|
|
|
// Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).
|
|
|
@@ -6984,11 +6987,12 @@ void ImGui::EndMenu()
|
|
|
// However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
- if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
|
|
- {
|
|
|
- ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
|
|
- NavMoveRequestCancel();
|
|
|
- }
|
|
|
+ if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
|
|
+ if (g.NavWindow && (g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow == window)
|
|
|
+ {
|
|
|
+ ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
|
|
+ NavMoveRequestCancel();
|
|
|
+ }
|
|
|
|
|
|
EndPopup();
|
|
|
}
|
|
|
@@ -7009,7 +7013,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
|
|
|
bool pressed;
|
|
|
PushID(label);
|
|
|
if (!enabled)
|
|
|
- BeginDisabled(true);
|
|
|
+ BeginDisabled();
|
|
|
const ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover;
|
|
|
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
|
|
|
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
|