mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-31 03:20:05 +00:00
Merge branch 'master' into docking
# Conflicts: # docs/CHANGELOG.txt # imgui.cpp # imgui_widgets.cpp
This commit is contained in:
commit
9cd9c2eff9
11 changed files with 211 additions and 190 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.88 WIP
|
||||
// dear imgui, v1.88
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
|
|
@ -1548,7 +1548,7 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
|||
width_excess -= width_to_remove_per_item * count_same_width;
|
||||
}
|
||||
|
||||
// Round width and redistribute remainder left-to-right (could make it an option of the function?)
|
||||
// Round width and redistribute remainder
|
||||
// Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator.
|
||||
width_excess = 0.0f;
|
||||
for (int n = 0; n < count; n++)
|
||||
|
|
@ -1557,10 +1557,13 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
|||
width_excess += items[n].Width - width_rounded;
|
||||
items[n].Width = width_rounded;
|
||||
}
|
||||
if (width_excess > 0.0f)
|
||||
while (width_excess > 0.0f)
|
||||
for (int n = 0; n < count; n++)
|
||||
if (items[n].Index < (int)(width_excess + 0.01f))
|
||||
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
||||
{
|
||||
items[n].Width += 1.0f;
|
||||
width_excess -= 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
@ -2623,7 +2626,6 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
|
|||
v_max_fudged = -logarithmic_zero_epsilon;
|
||||
|
||||
float result;
|
||||
|
||||
if (v_clamped <= v_min_fudged)
|
||||
result = 0.0f; // Workaround for values that are in-range but below our fudge
|
||||
else if (v_clamped >= v_max_fudged)
|
||||
|
|
@ -2647,91 +2649,81 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
|
|||
|
||||
return flipped ? (1.0f - result) : result;
|
||||
}
|
||||
|
||||
// Linear slider
|
||||
return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));
|
||||
else
|
||||
{
|
||||
// Linear slider
|
||||
return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)
|
||||
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
|
||||
TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
|
||||
{
|
||||
if (v_min == v_max)
|
||||
// We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct"
|
||||
// but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler.
|
||||
if (t <= 0.0f || v_min == v_max)
|
||||
return v_min;
|
||||
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
|
||||
if (t >= 1.0f)
|
||||
return v_max;
|
||||
|
||||
TYPE result;
|
||||
TYPE result = (TYPE)0;
|
||||
if (is_logarithmic)
|
||||
{
|
||||
// We special-case the extents because otherwise our fudging can lead to "mathematically correct" but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value
|
||||
if (t <= 0.0f)
|
||||
result = v_min;
|
||||
else if (t >= 1.0f)
|
||||
result = v_max;
|
||||
else
|
||||
// Fudge min/max to avoid getting silly results close to zero
|
||||
FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
|
||||
FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;
|
||||
|
||||
const bool flipped = v_max < v_min; // Check if range is "backwards"
|
||||
if (flipped)
|
||||
ImSwap(v_min_fudged, v_max_fudged);
|
||||
|
||||
// Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon)
|
||||
if ((v_max == 0.0f) && (v_min < 0.0f))
|
||||
v_max_fudged = -logarithmic_zero_epsilon;
|
||||
|
||||
float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range
|
||||
|
||||
if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts
|
||||
{
|
||||
bool flipped = v_max < v_min; // Check if range is "backwards"
|
||||
|
||||
// Fudge min/max to avoid getting silly results close to zero
|
||||
FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
|
||||
FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;
|
||||
|
||||
if (flipped)
|
||||
ImSwap(v_min_fudged, v_max_fudged);
|
||||
|
||||
// Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon)
|
||||
if ((v_max == 0.0f) && (v_min < 0.0f))
|
||||
v_max_fudged = -logarithmic_zero_epsilon;
|
||||
|
||||
float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range
|
||||
|
||||
if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts
|
||||
{
|
||||
float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space
|
||||
float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
|
||||
float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
|
||||
if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R)
|
||||
result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise)
|
||||
else if (t_with_flip < zero_point_center)
|
||||
result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L))));
|
||||
else
|
||||
result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R))));
|
||||
}
|
||||
else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider
|
||||
result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip)));
|
||||
float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space
|
||||
float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
|
||||
float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
|
||||
if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R)
|
||||
result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise)
|
||||
else if (t_with_flip < zero_point_center)
|
||||
result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L))));
|
||||
else
|
||||
result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));
|
||||
result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R))));
|
||||
}
|
||||
else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider
|
||||
result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip)));
|
||||
else
|
||||
result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Linear slider
|
||||
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
|
||||
if (is_floating_point)
|
||||
{
|
||||
result = ImLerp(v_min, v_max, t);
|
||||
}
|
||||
else
|
||||
else if (t < 1.0)
|
||||
{
|
||||
// - For integer values we want the clicking position to match the grab box so we round above
|
||||
// This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property..
|
||||
// - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64
|
||||
// range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits.
|
||||
if (t < 1.0)
|
||||
{
|
||||
FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t;
|
||||
result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = v_max;
|
||||
}
|
||||
FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t;
|
||||
result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME: Move more of the code into SliderBehavior()
|
||||
// FIXME: Try to move more of the code into shared SliderBehavior()
|
||||
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
|
||||
bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
|
||||
{
|
||||
|
|
@ -2741,13 +2733,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
|||
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
|
||||
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
|
||||
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
|
||||
const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
|
||||
|
||||
const float grab_padding = 2.0f;
|
||||
// Calculate bounds
|
||||
const float grab_padding = 2.0f; // FIXME: Should be part of style.
|
||||
const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;
|
||||
float grab_sz = style.GrabMinSize;
|
||||
SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
|
||||
if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows
|
||||
grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit
|
||||
if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows
|
||||
grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit
|
||||
grab_sz = ImMin(grab_sz, slider_sz);
|
||||
const float slider_usable_sz = slider_sz - grab_sz;
|
||||
const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;
|
||||
|
|
@ -2778,7 +2771,17 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
|||
else
|
||||
{
|
||||
const float mouse_abs_pos = g.IO.MousePos[axis];
|
||||
clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f;
|
||||
if (g.ActiveIdIsJustActivated)
|
||||
{
|
||||
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
|
||||
if (axis == ImGuiAxis_Y)
|
||||
grab_t = 1.0f - grab_t;
|
||||
const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
|
||||
const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here.
|
||||
g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f;
|
||||
}
|
||||
if (slider_usable_sz > 0.0f)
|
||||
clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz);
|
||||
if (axis == ImGuiAxis_Y)
|
||||
clicked_t = 1.0f - clicked_t;
|
||||
set_new_value = true;
|
||||
|
|
@ -4872,7 +4875,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
|||
|
||||
void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
|
||||
{
|
||||
#ifndef IMGUI_DISABLE_METRICS_WINDOW
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImStb::STB_TexteditState* stb_state = &state->Stb;
|
||||
ImStb::StbUndoState* undo_state = &stb_state->undostate;
|
||||
|
|
@ -7569,8 +7572,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
|
||||
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
|
||||
const char* tab_name = tab_bar->GetTabName(tab);
|
||||
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0;
|
||||
tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x;
|
||||
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
|
||||
tab->ContentWidth = (tab->RequestedWidth > 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button).x;
|
||||
|
||||
int section_n = TabItemGetSectionIdx(tab);
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
|
|
@ -7579,9 +7582,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||
|
||||
// Store data so we can build an array sorted by width if we need to shrink tabs down
|
||||
IM_MSVC_WARNING_SUPPRESS(6385);
|
||||
int shrink_buffer_index = shrink_buffer_indexes[section_n]++;
|
||||
g.ShrinkWidthBuffer[shrink_buffer_index].Index = tab_n;
|
||||
g.ShrinkWidthBuffer[shrink_buffer_index].Width = tab->ContentWidth;
|
||||
ImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++];
|
||||
shrink_width_item->Index = tab_n;
|
||||
shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth;
|
||||
|
||||
IM_ASSERT(tab->ContentWidth > 0.0f);
|
||||
tab->Width = tab->ContentWidth;
|
||||
|
|
@ -8092,10 +8095,13 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags)
|
|||
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
|
||||
{
|
||||
// Layout whole tab bar if not already done
|
||||
if (tab_bar->WantLayout)
|
||||
TabBarLayout(tab_bar);
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (tab_bar->WantLayout)
|
||||
{
|
||||
ImGuiNextItemData backup_next_item_data = g.NextItemData;
|
||||
TabBarLayout(tab_bar);
|
||||
g.NextItemData = backup_next_item_data;
|
||||
}
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
|
@ -8121,9 +8127,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|||
else if (p_open == NULL)
|
||||
flags |= ImGuiTabItemFlags_NoCloseButton;
|
||||
|
||||
// Calculate tab contents size
|
||||
ImVec2 size = TabItemCalcSize(label, p_open != NULL);
|
||||
|
||||
// Acquire tab data
|
||||
ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id);
|
||||
bool tab_is_new = false;
|
||||
|
|
@ -8132,11 +8135,17 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|||
tab_bar->Tabs.push_back(ImGuiTabItem());
|
||||
tab = &tab_bar->Tabs.back();
|
||||
tab->ID = id;
|
||||
tab->Width = size.x;
|
||||
tab_bar->TabsAddedNew = true;
|
||||
tab_is_new = true;
|
||||
tab_bar->TabsAddedNew = tab_is_new = true;
|
||||
}
|
||||
tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab);
|
||||
|
||||
// Calculate tab contents size
|
||||
ImVec2 size = TabItemCalcSize(label, p_open != NULL);
|
||||
tab->RequestedWidth = -1.0f;
|
||||
if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
|
||||
size.x = tab->RequestedWidth = g.NextItemData.Width;
|
||||
if (tab_is_new)
|
||||
tab->Width = size.x;
|
||||
tab->ContentWidth = size.x;
|
||||
tab->BeginOrder = tab_bar->TabsActiveCount++;
|
||||
|
||||
|
|
@ -8163,13 +8172,14 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|||
}
|
||||
|
||||
// Update selected tab
|
||||
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
|
||||
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
|
||||
if (!is_tab_button)
|
||||
if (!is_tab_button)
|
||||
{
|
||||
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
|
||||
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
|
||||
tab_bar->NextSelectedTabId = id; // New tabs gets activated
|
||||
if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar
|
||||
if (!is_tab_button)
|
||||
if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar
|
||||
tab_bar->NextSelectedTabId = id;
|
||||
}
|
||||
|
||||
// Lock visibility
|
||||
// (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue