Merge branch 'master' into docking

# Conflicts:
#	examples/example_sdl_opengl2/main.cpp
#	examples/example_sdl_opengl3/main.cpp
#	examples/example_sdl_vulkan/main.cpp
#	examples/imgui_impl_sdl.cpp
#	examples/imgui_impl_sdl.h
#	imgui.cpp
This commit is contained in:
omar
2019-04-25 17:53:11 +02:00
17 changed files with 194 additions and 109 deletions

View File

@ -2020,8 +2020,6 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
if (!ItemAdd(total_bb, id, &frame_bb))
return false;
const bool hovered = ItemHoverable(frame_bb, id);
// Default format string when passing NULL
// Patch old "%.0f" format string to use "%d", read function comments for more details.
IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
@ -2031,37 +2029,40 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
format = PatchFormatStringFloatToInt(format);
// Tabbing or CTRL-clicking on Drag turns it into an input box
bool start_text_input = false;
const bool focus_requested = FocusableItemRegister(window, id);
if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
const bool hovered = ItemHoverable(frame_bb, id);
bool temp_input_is_active = TempInputTextIsActive(id);
bool temp_input_start = false;
if (!temp_input_is_active)
{
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id)
const bool focus_requested = FocusableItemRegister(window, id);
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)
{
start_text_input = true;
g.ScalarAsInputTextId = 0;
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)
{
temp_input_start = true;
FocusableItemUnregister(window);
}
}
}
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
{
window->DC.CursorPos = frame_bb.Min;
FocusableItemUnregister(window);
return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
}
// Actual drag behavior
const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None);
if (value_changed)
MarkItemEdited(id);
if (temp_input_is_active || temp_input_start)
return TempInputTextScalar(frame_bb, id, label, data_type, v, format);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
// Drag behavior
const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None);
if (value_changed)
MarkItemEdited(id);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
@ -2473,27 +2474,28 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
format = PatchFormatStringFloatToInt(format);
// Tabbing or CTRL-clicking on Slider turns it into an input box
bool start_text_input = false;
const bool focus_requested = FocusableItemRegister(window, id);
const bool hovered = ItemHoverable(frame_bb, id);
if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
bool temp_input_is_active = TempInputTextIsActive(id);
bool temp_input_start = false;
if (!temp_input_is_active)
{
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id)
const bool focus_requested = FocusableItemRegister(window, id);
const bool clicked = (hovered && g.IO.MouseClicked[0]);
if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
{
start_text_input = true;
g.ScalarAsInputTextId = 0;
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)
{
temp_input_start = true;
FocusableItemUnregister(window);
}
}
}
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
{
window->DC.CursorPos = frame_bb.Min;
FocusableItemUnregister(window);
return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
}
if (temp_input_is_active || temp_input_start)
return TempInputTextScalar(frame_bb, id, label, data_type, v, format);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@ -2679,7 +2681,7 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min,
// - ImParseFormatFindEnd() [Internal]
// - ImParseFormatTrimDecorations() [Internal]
// - ImParseFormatPrecision() [Internal]
// - InputScalarAsWidgetReplacement() [Internal]
// - TempInputTextScalar() [Internal]
// - InputScalar()
// - InputScalarN()
// - InputFloat()
@ -2765,16 +2767,16 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
return (precision == INT_MAX) ? default_precision : precision;
}
// Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets)
// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets)
// FIXME: Facilitate using this in variety of other situations.
bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
{
IM_UNUSED(id);
ImGuiContext& g = *GImGui;
// On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id.
// On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id.
// We clear ActiveID on the first frame to allow the InputText() taking it back.
if (g.ScalarAsInputTextId == 0)
const bool init = (g.TempInputTextId != id);
if (init)
ClearActiveID();
char fmt_buf[32];
@ -2782,13 +2784,15 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c
format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format);
ImStrTrimBlanks(data_buf);
g.CurrentWindow->DC.CursorPos = bb.Min;
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((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);
if (g.ScalarAsInputTextId == 0)
if (init)
{
// First frame we started displaying the InputText widget, we expect it to take the active id.
IM_ASSERT(g.ActiveId == id);
g.ScalarAsInputTextId = g.ActiveId;
g.TempInputTextId = g.ActiveId;
}
if (value_changed)
return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
@ -5107,7 +5111,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
window->DC.TreeStoreMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
bool item_add = ItemAdd(interact_bb, id);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
@ -5116,7 +5120,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (!item_add)
{
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushRawID(id);
TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@ -5220,7 +5224,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
}
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushRawID(id);
TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@ -5241,7 +5245,7 @@ void ImGui::TreePush(const void* ptr_id)
PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
}
void ImGui::TreePushRawID(ImGuiID id)
void ImGui::TreePushOverrideID(ImGuiID id)
{
ImGuiWindow* window = GetCurrentWindow();
Indent();
@ -5257,12 +5261,12 @@ void ImGui::TreePop()
window->DC.TreeDepth--;
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
if (g.NavIdIsAlive && (window->DC.TreeStoreMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
{
SetNavID(window->IDStack.back(), g.NavLayer);
NavMoveRequestCancel();
}
window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
window->DC.TreeStoreMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
PopID();
@ -5439,7 +5443,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
bb.Max.x -= (GetContentRegionMax().x - max_x);
}
if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
RenderTextClipped(bb_inner.Min, bb_inner.Max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
@ -5913,10 +5917,11 @@ void ImGui::EndMenuBar()
{
// 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)
IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check
const ImGuiNavLayer layer = ImGuiNavLayer_Menu;
IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); // Sanity check
FocusWindow(window);
SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]);
g.NavLayer = ImGuiNavLayer_Menu;
SetNavIDWithRectRel(window->NavLastIds[layer], layer, window->NavRectRel[layer]);
g.NavLayer = layer;
g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
NavMoveRequestCancel();
@ -5966,7 +5971,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
popup_pos = ImVec2(pos.x - 1.0f - (float)(int)(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight());
window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
float w = label_size.x;
pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
PopStyleVar();
@ -6110,7 +6115,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo
// Note that in this situation we render neither the shortcut neither the selected tick mark
float w = label_size.x;
window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
pressed = Selectable(label, false, flags, ImVec2(w, 0.0f));
PopStyleVar();
window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
@ -6246,7 +6251,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
return false;
if ((flags & ImGuiTabBarFlags_DockNode) == 0)
window->IDStack.push_back(tab_bar->ID);
PushOverrideID(tab_bar->ID);
// Add to stack
g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar));
@ -6741,7 +6746,8 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags)
{
ImGuiContext& g = *GImGui;
if (g.CurrentWindow->SkipItems)
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return false;
ImGuiTabBar* tab_bar = g.CurrentTabBar;
@ -6754,7 +6760,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
g.CurrentWindow->IDStack.push_back(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label)
PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label)
}
return ret;
}
@ -6762,7 +6768,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
void ImGui::EndTabItem()
{
ImGuiContext& g = *GImGui;
if (g.CurrentWindow->SkipItems)
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return;
ImGuiTabBar* tab_bar = g.CurrentTabBar;
@ -6774,7 +6781,7 @@ void ImGui::EndTabItem()
IM_ASSERT(tab_bar->LastTabItemIdx >= 0);
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
if (!(tab->Flags & ImGuiTabItemFlags_NoPushId))
g.CurrentWindow->IDStack.pop_back();
window->IDStack.pop_back();
}
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)