diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 274ca2a6..eea8eaa3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -389,8 +389,8 @@ jobs:
wget -q https://github.com/emscripten-core/emsdk/archive/master.tar.gz
tar -xvf master.tar.gz
emsdk-master/emsdk update
- emsdk-master/emsdk install latest-fastcomp
- emsdk-master/emsdk activate latest-fastcomp
+ emsdk-master/emsdk install latest
+ emsdk-master/emsdk activate latest
- name: Build example_emscripten
run: |
@@ -398,38 +398,3 @@ jobs:
source ./emsdk_env.sh
popd
make -C examples/example_emscripten
-
- Static-Analysis:
- runs-on: ubuntu-18.04
- steps:
- - uses: actions/checkout@v1
- with:
- fetch-depth: 1
-
- - name: Install Dependencies
- env:
- PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }}
- run: |
- if [[ "$PVS_STUDIO_LICENSE" != "" ]];
- then
- echo "$PVS_STUDIO_LICENSE" > pvs-studio.lic
- wget -q https://files.viva64.com/etc/pubkey.txt
- sudo apt-key add pubkey.txt
- sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
- sudo apt-get update
- sudo apt-get install -y pvs-studio
- fi
-
- - name: PVS-Studio static analysis
- run: |
- if [[ ! -f pvs-studio.lic ]];
- then
- echo "PVS Studio license is missing. No analysis will be performed."
- echo "If you have a PVS Studio license please create a project secret named PVS_STUDIO_LICENSE with your license."
- echo "You may use a free license. More information at https://www.viva64.com/en/b/0457/"
- exit 0
- fi
- cd examples/example_null
- pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
- pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
- plog-converter -a 'GA:1,2;OP:1' -t errorfile -w pvs-studio.log
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
new file mode 100644
index 00000000..7967d532
--- /dev/null
+++ b/.github/workflows/static-analysis.yml
@@ -0,0 +1,43 @@
+name: static-analysis
+
+on:
+ push: {}
+ pull_request: {}
+ schedule:
+ - cron: '0 9 * * *'
+
+jobs:
+ PVS-Studio:
+ runs-on: ubuntu-18.04
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ fetch-depth: 1
+
+ - name: Install Dependencies
+ env:
+ PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }}
+ run: |
+ if [[ "$PVS_STUDIO_LICENSE" != "" ]];
+ then
+ echo "$PVS_STUDIO_LICENSE" > pvs-studio.lic
+ wget -q https://files.viva64.com/etc/pubkey.txt
+ sudo apt-key add pubkey.txt
+ sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
+ sudo apt-get update
+ sudo apt-get install -y pvs-studio
+ fi
+
+ - name: PVS-Studio static analysis
+ run: |
+ if [[ ! -f pvs-studio.lic ]];
+ then
+ echo "PVS Studio license is missing. No analysis will be performed."
+ echo "If you have a PVS Studio license please create a project secret named PVS_STUDIO_LICENSE with your license."
+ echo "You may use a free license. More information at https://www.viva64.com/en/b/0457/"
+ exit 0
+ fi
+ cd examples/example_null
+ pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
+ pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
+ plog-converter -a 'GA:1,2;OP:1' -t errorfile -w pvs-studio.log
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 65836821..6a9ed9e6 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -104,6 +104,34 @@ Other changes:
VERSION 1.78 WIP (In Progress)
-----------------------------------------------------------------------
+Breaking Changes:
+
+- Obsoleted use of the trailing 'float power=1.0f' parameter for those functions: [@Shironekoben, @ocornut]
+ - DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN()
+ - SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN()
+ - VSliderFloat(), VSliderScalar()
+ Replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
+ The type of those flags are ImGuiDragFlags and ImGuiSliderFlags (underlying int storage).
+ Worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected.
+ In short, when calling those functions:
+ - If you omitted the 'power' parameter (likely!), you are not affected.
+ - If you set the 'power' parameter to 1.0f (same as previous default value):
+ - Your compiler may warn on float>int conversion.
+ - Everything else will work.
+ - You can replace the 1.0f value with 0 to fix the warning, and be technically correct.
+ - If you set the 'power' parameter to >1.0f (to enable non-linear editing):
+ - Your compiler may warn on float>int conversion.
+ - Code will assert at runtime for IM_ASSERT(power == 1.0f) with the following assert description:
+ "Call Drag function with ImGuiDragFlags_Logarithmic instead of using the old 'float power' function!".
+ - In case asserts are disabled, the code will not crash and enable the _Logarithmic flag.
+ - You can replace the >1.0f value with ImGuiDragFlags_Logarithmic or ImGuiSliderFlags_Logarithmic
+ to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
+ See https://github.com/ocornut/imgui/issues/3361 for all details.
+ Kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar().
+ For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
+- DragInt, DragFloat, DragScalar: Obsoleted use of v_min > v_max to lock edits (introduced in 1.73, this was not
+ demoed nor documented much, will be replaced a more generic ReadOnly feature).
+
Other Changes:
- Nav: Fixed clicking on void (behind any windows) from not clearing the focused window.
@@ -111,6 +139,20 @@ Other Changes:
flag being cleared accordingly. (bug introduced in 1.77 WIP on 2020/06/16) (#3344, #2880)
- Window: Fixed clicking over an item which hovering has been disabled (e.g inhibited by a popup)
from marking the window as moved.
+- Drag, Slider: Added ImGuiDragFlags and ImGuiSliderFlags parameters.
+ For float functions they replace the old trailing 'float power=1.0' parameter.
+ (See #3361 and the "Breaking Changes" block above for all details).
+- Drag, Slider: Added ImGuiDragFlags_Logarithmic/ImGuiSliderFlags_Logarithmic flags to
+ enable logarithmic editing (generally more precision around zero), as a replacement to the old
+ 'float power' parameter which was obsoleted. (#1823, #1316, #642) [@Shironekoben, @AndrewBelt]
+- Drag, Slider: Added ImGuiDragFlags_ClampOnInput/ImGuiSliderFlags_ClampOnInput flags to force
+ clamping value when using CTRL+Click to type in a value manually. (#1829, #3209, #946, #413).
+- Drag, Slider: Added ImGuiDragFlags_NoRoundToFormat/ImGuiSliderFlags_NoRoundToFormat flags
+ to disable rounding underlying value to match precision of the display format string. (#642)
+- Drag, Slider: Added ImGuiDragFlags_NoInput/ImGuiSliderFlags_NoInput to disable turning
+ widget into a text input with CTRL+Click or Nav Enter.
+- Nav, Slider: Fix using keyboard/gamepad controls with certain logarithmic sliders where
+ pushing a direction near zero values would be cancelled out. [@Shironekoben]
- DragFloatRange2, DragIntRange2: Fixed an issue allowing to drag out of bounds when both
min and max value are on the same value. (#1441)
- InputText, ImDrawList: Fixed assert triggering when drawing single line of text with more
@@ -124,6 +166,7 @@ Other Changes:
limits when close-enough by (WindowPadding - ItemPadding), which was a tweak with too many
side-effects. The behavior is still present in SetScrollHere functions as they are more explicitly
aiming at making widgets visible. May later be moved to a flag.
+- Tab Bar: Allow calling SetTabItemClosed() after a tab has been submitted (will process next frame).
- InvisibleButton: Made public a small selection of ImGuiButtonFlags (previously in imgui_internal.h)
and allowed to pass them to InvisibleButton(): ImGuiButtonFlags_MouseButtonLeft/Right/Middle.
This is a small but rather important change because lots of multi-button behaviors could previously
@@ -149,7 +192,10 @@ Other Changes:
- Demo: Improved "Layout & Scrolling" -> "Child Windows" section.
- Style Editor: Added preview of circle auto-tessellation when editing the corresponding value.
- Backends: OpenGL3: Added support for glad2 loader. (#3330) [@moritz-h]
+- Backends: Allegro 5: Fixed horizontal scrolling direction with mouse wheel / touch pads (it seems
+ like Allegro 5 reports it differently from GLFW and SDL). (#3394, #2424, #1463) [@nobody-special666]
- Examples: Vulkan: Fixed GLFW+Vulkan and SDL+Vulkan clear color not being set. (#3390) [@RoryO]
+- CI: Emscripten has stopped their support for their fastcomp backend, switching to latest sdk [@Xipiryon]
-----------------------------------------------------------------------
diff --git a/docs/README.md b/docs/README.md
index 9579ee22..58fb208e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,6 +1,7 @@
Dear ImGui
=====
-[![Build Status](https://github.com/ocornut/imgui/workflows/build/badge.svg)](https://github.com/ocornut/imgui/actions?workflow=build)
+[![Build Status](https://github.com/ocornut/imgui/workflows/build/badge.svg)](https://github.com/ocornut/imgui/actions?workflow=build) [![Static Analysis Status](https://github.com/ocornut/imgui/workflows/static-analysis/badge.svg)](https://github.com/ocornut/imgui/actions?workflow=static-analysis)
+
(This library is available under a free and permissive license, but needs financial support to sustain its continued improvements. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using Dear ImGui, please consider reaching out.)
@@ -97,7 +98,7 @@ Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcas
![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png)
You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here:
-- [imgui-demo-binaries-20190715.zip](http://www.dearimgui.org/binaries/imgui-demo-binaries-20200412.zip) (Windows binaries, 1.76, built 2020/04/12, master branch) or [older demo binaries](http://www.dearimgui.org/binaries).
+- [imgui-demo-binaries-20200412.zip](http://www.dearimgui.org/binaries/imgui-demo-binaries-20200412.zip) (Windows, 1.76, built 2020/04/12, master branch) or [older demo binaries](http://www.dearimgui.org/binaries).
The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at different scale, and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.org/faq)).
@@ -125,7 +126,7 @@ Some of the goals for 2020 are:
- Work on docking. (see [#2109](https://github.com/ocornut/imgui/issues/2109), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch)
- Work on multiple viewports / multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback)
- Work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787))
-- Work on new Tables API (to replace Columns). (see [#2957](https://github.com/ocornut/imgui/issues/2957))
+- Work on new Tables API (to replace Columns). (see [#2957](https://github.com/ocornut/imgui/issues/2957), in public [tables](https://github.com/ocornut/imgui/tree/tables) branch looking for feedback)
- Work on automation and testing system, both to test the library and end-user apps. (see [#435](https://github.com/ocornut/imgui/issues/435))
- Make the examples look better, improve styles, improve font support, make the examples hi-DPI and multi-DPI aware.
@@ -144,7 +145,7 @@ Custom engine
### Support, Frequently Asked Questions (FAQ)
-Most common questions will be answered by the [Frequently Asked Questions (FAQ)](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) page.
+See: [Frequently Asked Questions (FAQ)](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) where common questions are answered.
See: [Wiki](https://github.com/ocornut/imgui/wiki) for many links, references, articles.
@@ -160,7 +161,7 @@ Private support is available for paying business customers (E-mail: _contact @ d
We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
-You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features in the `docking` branch. Many projects are using this branch and it is kept in sync with master regularly.
+Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features. This branch is kept in sync with master regularly.
**Who uses Dear ImGui?**
@@ -219,7 +220,7 @@ Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT li
Embeds [stb_textedit.h, stb_truetype.h, stb_rect_pack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain).
-Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. And everybody posting feedback, questions and patches on the GitHub.
+Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Also thank you to everyone posting feedback, questions and patches on GitHub.
License
-------
diff --git a/docs/TODO.txt b/docs/TODO.txt
index 221a3306..41939c9a 100644
--- a/docs/TODO.txt
+++ b/docs/TODO.txt
@@ -189,6 +189,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- docking: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
- docking: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker.
+ - tabs: while dragging/reordering a tab, close button decoration shouldn't appear on other tabs
- tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing.
- tabs: persistent order/focus in BeginTabBar() api (#261, #351)
- tabs: TabItem could honor SetNextItemWidth()?
@@ -208,7 +209,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- slider: step option (#1183)
- slider style: fill % of the bar instead of positioning a drag.
- knob: rotating knob widget (#942)
- - drag float: power/logarithmic slider and drags are weird. (#1316)
+ - drag float: support for reversed drags (min > max) (removed is_locked, also see fdc526e)
- drag float: up/down axis
- drag float: power != 0.0f with current value being outside the range keeps the value stuck.
- drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits)
diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj
index c86dcb2b..f5fadc37 100644
--- a/examples/example_allegro5/example_allegro5.vcxproj
+++ b/examples/example_allegro5/example_allegro5.vcxproj
@@ -19,7 +19,7 @@
- {2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741}
+ {73F235B5-7D31-4FC6-8682-DDC5A097B9C1}
example_allegro5
8.1
diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp
index 4a467c30..ca2cfae4 100644
--- a/examples/imgui_impl_allegro5.cpp
+++ b/examples/imgui_impl_allegro5.cpp
@@ -15,6 +15,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
@@ -332,7 +333,7 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
if (ev->mouse.display == g_Display)
{
io.MouseWheel += ev->mouse.dz;
- io.MouseWheelH += ev->mouse.dw;
+ io.MouseWheelH -= ev->mouse.dw;
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
}
return true;
diff --git a/imgui.cpp b/imgui.cpp
index 13dfcc42..75699181 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -383,6 +383,15 @@ CODE
- 2020/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
+ - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
+ replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
+ worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
+ - if you omitted the 'power' parameter (likely!), you are not affected.
+ - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
+ - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiDragFlags_Logarithmic or ImGuiSliderFlags_Logarithmic flag to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
+ see https://github.com/ocornut/imgui/issues/3361 for all details.
+ kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used.
+ - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiDragFlags_ReadOnly internal flag in the meantime.
- 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
- 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete).
- 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
@@ -952,6 +961,7 @@ ImGuiStyle::ImGuiStyle()
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
+ LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
TabBorderSize = 0.0f; // Thickness of border around tabs.
TabMinWidthForUnselectedCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
@@ -991,6 +1001,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
GrabMinSize = ImFloor(GrabMinSize * scale_factor);
GrabRounding = ImFloor(GrabRounding * scale_factor);
+ LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
TabRounding = ImFloor(TabRounding * scale_factor);
if (TabMinWidthForUnselectedCloseButton != FLT_MAX)
TabMinWidthForUnselectedCloseButton = ImFloor(TabMinWidthForUnselectedCloseButton * scale_factor);
@@ -6720,7 +6731,7 @@ void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* current_front_window = g.Windows.back();
- if (current_front_window == window || current_front_window->RootWindow == window)
+ if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)
return;
for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
if (g.Windows[i] == window)
@@ -8421,13 +8432,14 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
}
}
+// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
+// This function closes any popups that are over 'ref_window'.
void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
{
ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size == 0)
return;
- // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
// Don't close our own child popup windows.
int popup_count_to_keep = 0;
if (ref_window)
@@ -8442,13 +8454,20 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
continue;
- // Trim the stack when popups are not direct descendant of the reference window (the reference window is often the NavWindow)
- bool popup_or_descendent_is_ref_window = false;
- for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_is_ref_window; m++)
- if (ImGuiWindow* popup_window = g.OpenPopupStack[m].Window)
+ // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
+ // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:
+ // Window -> Popup1 -> Popup2 -> Popup3
+ // - Each popups may contain child windows, which is why we compare ->RootWindow!
+ // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
+ bool ref_window_is_descendent_of_popup = false;
+ for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
+ if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
if (popup_window->RootWindow == ref_window->RootWindow)
- popup_or_descendent_is_ref_window = true;
- if (!popup_or_descendent_is_ref_window)
+ {
+ ref_window_is_descendent_of_popup = true;
+ break;
+ }
+ if (!ref_window_is_descendent_of_popup)
break;
}
}
diff --git a/imgui.h b/imgui.h
index aea28ff2..db033156 100644
--- a/imgui.h
+++ b/imgui.h
@@ -61,7 +61,7 @@ Index of this file:
// Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.78 WIP"
-#define IMGUI_VERSION_NUM 17703
+#define IMGUI_VERSION_NUM 17704
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch
#define IMGUI_HAS_DOCK 1 // Docking WIP branch
@@ -165,6 +165,7 @@ typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: f
typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags
typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo()
typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace()
+typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragFloat(), DragInt() etc.
typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload()
typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused()
typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
@@ -172,6 +173,7 @@ typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: f
typedef int ImGuiKeyModFlags; // -> enum ImGuiKeyModFlags_ // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super)
typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen()
typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
+typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderFloat(), SliderInt() etc.
typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar()
typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem()
typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader()
@@ -474,39 +476,45 @@ namespace ImGui
// - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
+ // - Format string may also be set to NULL or use the default format ("%f" or "%d").
// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
// - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits.
// - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum.
- IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound
- IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f);
- IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); // If v_min >= v_max we have no bound
- IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d");
- IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d");
- IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d");
- IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL);
- IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f);
- IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f);
+ // - Legacy: Pre-1.78 there are DragXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiDragFlags flags=0' argument.
+ // If you get a warning converting a float to ImGuiDragFlags, read https://github.com/ocornut/imgui/issues/3361
+ IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0); // If v_min >= v_max we have no bound
+ IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiDragFlags flags = 0); // If v_min >= v_max we have no bound
+ IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiDragFlags flags = 0);
+ IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiDragFlags flags = 0);
// Widgets: Sliders
// - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
- IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders
- IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg");
- IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
- IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
- IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
- IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
+ // - Format string may also be set to NULL or use the default format ("%f" or "%d").
+ // - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.
+ // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361
+ IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display.
+ IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
+ IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
+ IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
+ IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
// Widgets: Input with Keyboard
// - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp.
@@ -1357,6 +1365,28 @@ enum ImGuiColorEditFlags_
#endif
};
+// Flags for DragFloat(), DragInt() etc.
+enum ImGuiDragFlags_
+{
+ ImGuiDragFlags_None = 0,
+ ImGuiDragFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
+ ImGuiDragFlags_ClampOnInput = 1 << 4, // Clamp value to min/max bounds (if any) when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
+ ImGuiDragFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiDragFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
+ ImGuiDragFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
+ ImGuiDragFlags_NoInput = 1 << 7 // Disable CTRL+Click or Enter key allowing to input text directly into the widget
+};
+
+// Flags for SliderFloat(), SliderInt() etc.
+enum ImGuiSliderFlags_
+{
+ ImGuiSliderFlags_None = 0,
+ ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
+ ImGuiSliderFlags_ClampOnInput = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
+ ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
+ ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
+ ImGuiSliderFlags_NoInput = 1 << 7 // Disable CTRL+Click or Enter key allowing to input text directly into the widget
+};
+
// Identify a mouse button.
// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience.
enum ImGuiMouseButton_
@@ -1518,6 +1548,7 @@ struct ImGuiStyle
float ScrollbarRounding; // Radius of grab corners for scrollbar.
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
+ float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
float TabBorderSize; // Thickness of border around tabs.
float TabMinWidthForUnselectedCloseButton; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
@@ -1789,6 +1820,20 @@ struct ImGuiPayload
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui
{
+ // OBSOLETED in 1.78 (from August 2020)
+ // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags
+ IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power);
+ IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power);
+ static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); }
+ static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); }
+ static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); }
+ static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); }
+ IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power);
+ IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power);
+ static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); }
+ static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); }
+ static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); }
+ static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); }
// OBSOLETED in 1.77 (from June 2020)
static inline bool OpenPopupOnItemClick(const char* str_id = NULL, ImGuiMouseButton mb = 1) { return OpenPopupContextItem(str_id, mb); } // Passing a mouse button to ImGuiPopupFlags is legal
static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); }
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 7b240696..60237481 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -684,7 +684,7 @@ static void ShowDemoWindowWidgets()
static float f1 = 0.123f, f2 = 0.0f;
ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
- ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f);
+ ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
static float angle = 0.0f;
ImGui::SliderAngle("slider angle", &angle);
@@ -1543,11 +1543,53 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
+ if (ImGui::TreeNode("Drag/Slider Flags"))
+ {
+ // Demonstrate using advanced flags for DragXXX functions
+ static ImGuiDragFlags drag_flags = ImGuiDragFlags_None;
+ ImGui::CheckboxFlags("ImGuiDragFlags_ClampOnInput", (unsigned int*)&drag_flags, ImGuiDragFlags_ClampOnInput);
+ ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
+ ImGui::CheckboxFlags("ImGuiDragFlags_Logarithmic", (unsigned int*)&drag_flags, ImGuiDragFlags_Logarithmic);
+ ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
+ ImGui::CheckboxFlags("ImGuiDragFlags_NoRoundToFormat", (unsigned int*)&drag_flags, ImGuiDragFlags_NoRoundToFormat);
+ ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
+ ImGui::CheckboxFlags("ImGuiDragFlags_NoInput", (unsigned int*)&drag_flags, ImGuiDragFlags_NoInput);
+ ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
+
+ static float drag_f = 0.5f;
+ static int drag_i = 50;
+ ImGui::Text("Underlying float value: %f", drag_f);
+ ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", drag_flags);
+ ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", drag_flags);
+ ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", drag_flags);
+ ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", drag_flags);
+ ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", drag_flags);
+
+ // Demonstrate using advanced flags for SliderXXX functions
+ static ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
+ ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", (unsigned int*)&slider_flags, ImGuiSliderFlags_ClampOnInput);
+ ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&slider_flags, ImGuiSliderFlags_Logarithmic);
+ ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&slider_flags, ImGuiSliderFlags_NoRoundToFormat);
+ ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&slider_flags, ImGuiSliderFlags_NoInput);
+ ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
+
+ static float slider_f = 0.5f;
+ static int slider_i = 50;
+ ImGui::Text("Underlying float value: %f", slider_f);
+ ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", slider_flags);
+ ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%.3f", slider_flags);
+
+ ImGui::TreePop();
+ }
+
if (ImGui::TreeNode("Range Widgets"))
{
static float begin = 10, end = 90;
static int begin_i = 100, end_i = 1000;
- ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
+ ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiDragFlags_ClampOnInput);
ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
ImGui::TreePop();
@@ -1612,34 +1654,34 @@ static void ShowDemoWindowWidgets()
ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
- ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f);
- ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); HelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range.");
- ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f);
- ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f);
+ ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
+ ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiDragFlags_Logarithmic);
+ ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
+ ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiDragFlags_Logarithmic);
ImGui::Text("Sliders");
- ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
- ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
- ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
- ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
- ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
- ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
- ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
- ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
- ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
- ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
- ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d");
- ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d");
- ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d");
- ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms");
- ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms");
- ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms");
- ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
- ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f);
- ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
- ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f);
- ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f);
- ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f);
+ ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
+ ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
+ ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
+ ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
+ ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
+ ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
+ ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
+ ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
+ ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
+ ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
+ ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d");
+ ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d");
+ ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d");
+ ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms");
+ ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms");
+ ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms");
+ ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
+ ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiDragFlags_Logarithmic);
+ ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
+ ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
+ ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiDragFlags_Logarithmic);
+ ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
static bool inputs_step = true;
ImGui::Text("Inputs");
@@ -3824,6 +3866,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
@@ -3935,10 +3978,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
"rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
"Using those settings here will give you poor quality results.");
static float window_scale = 1.0f;
- if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale only this window
- ImGui::SetWindowFontScale(IM_MAX(window_scale, MIN_SCALE));
- if (ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale everything
- io.FontGlobalScale = IM_MAX(io.FontGlobalScale, MIN_SCALE);
+ if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiDragFlags_ClampOnInput)) // Scale only this window
+ ImGui::SetWindowFontScale(window_scale);
+ ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiDragFlags_ClampOnInput); // Scale everything
ImGui::PopItemWidth();
ImGui::EndTabItem();
diff --git a/imgui_internal.h b/imgui_internal.h
index 2dada7af..556386ef 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -119,7 +119,6 @@ typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // E
typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior()
typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: BeginColumns()
-typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior()
typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag()
typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags
typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
@@ -128,7 +127,6 @@ typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // F
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 ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx()
typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx()
@@ -360,6 +358,12 @@ IMGUI_API void* ImFileLoadToMemory(const char* filename, const char*
#define ImCeil(X) ceilf(X)
static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision
static inline double ImPow(double x, double y) { return pow(x, y); }
+static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision
+static inline double ImLog(double x) { return log(x); }
+static inline float ImAbs(float x) { return fabsf(x); }
+static inline double ImAbs(double x) { return fabs(x); }
+static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument
+static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); }
#endif
// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double
// (Exceptionally using templates here but we could also redefine them for those types)
@@ -639,16 +643,18 @@ enum ImGuiButtonFlagsPrivate_
ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease
};
-enum ImGuiSliderFlags_
+// Extend ImGuiDragFlags_
+enum ImGuiDragFlagsPrivate_
{
- ImGuiSliderFlags_None = 0,
- ImGuiSliderFlags_Vertical = 1 << 0
+ ImGuiDragFlags_Vertical = 1 << 20, // Should this widget be orientated vertically?
+ ImGuiDragFlags_ReadOnly = 1 << 21
};
-enum ImGuiDragFlags_
+// Extend ImGuiSliderFlags_
+enum ImGuiSliderFlagsPrivate_
{
- ImGuiDragFlags_None = 0,
- ImGuiDragFlags_Vertical = 1 << 0
+ ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically?
+ ImGuiSliderFlags_ReadOnly = 1 << 21
};
// Extend ImGuiSelectableFlags_
@@ -1293,11 +1299,11 @@ struct ImGuiContext
ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
int WindowsActiveCount; // Number of unique windows submitted by frame
ImGuiWindow* CurrentWindow; // Window being drawn into
- ImGuiWindow* HoveredWindow; // Will catch mouse inputs
- ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
+ ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
+ ImGuiWindow* HoveredRootWindow; // == HoveredWindow ? HoveredWindow->RootWindow : NULL, merely a shortcut to avoid null test in some situation.
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
ImGuiDockNode* HoveredDockNode;
- ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
+ ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow.
ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
ImVec2 WheelingWindowRefMousePos;
float WheelingWindowTimer;
@@ -1448,6 +1454,8 @@ struct ImGuiContext
float ColorEditLastSat; // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips
float ColorEditLastColor[3];
ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker.
+ float SliderCurrentAccum; // Accumulated slider delta when using navigation controls.
+ bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it?
bool DragCurrentAccumDirty;
float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
@@ -1531,6 +1539,7 @@ struct ImGuiContext
ActiveIdTimer = 0.0f;
ActiveIdIsJustActivated = false;
ActiveIdAllowOverlap = false;
+ ActiveIdNoClearOnFocusLoss = false;
ActiveIdHasBeenPressedBefore = false;
ActiveIdHasBeenEditedBefore = false;
ActiveIdHasBeenEditedThisFrame = false;
@@ -1611,6 +1620,8 @@ struct ImGuiContext
ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
ColorEditLastHue = ColorEditLastSat = 0.0f;
ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX;
+ SliderCurrentAccum = 0.0f;
+ SliderCurrentAccumDirty = false;
DragCurrentAccumDirty = false;
DragCurrentAccum = 0.0f;
DragSpeedDefaultRatio = 1.0f / 100.0f;
@@ -1824,7 +1835,7 @@ struct IMGUI_API ImGuiWindow
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
ImDrawList DrawListInst;
ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
- ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window.
+ ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window == Top-level window.
ImGuiWindow* RootWindowDockStop; // Point to ourself or first ancestor that is not a child window. Doesn't cross through dock nodes. We use this so IsWindowFocused() can behave consistently regardless of docking state.
ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
@@ -1910,12 +1921,13 @@ struct ImGuiTabItem
ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window.
int LastFrameVisible;
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
- int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
float Offset; // Position relative to beginning of tab
float Width; // Width currently displayed
float ContentWidth; // Width of actual contents, stored during BeginTabItem() call
+ ImS16 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
+ bool WantClose; // Marked as closed by SetTabItemClosed()
- ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; }
+ ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; WantClose = false; }
};
// Storage for a tab bar (sizeof() 92~96 bytes)
@@ -1952,7 +1964,7 @@ struct ImGuiTabBar
{
if (tab->Window)
return tab->Window->Name;
- IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size);
+ IM_ASSERT(tab->NameOffset != -1 && (int)tab->NameOffset < TabsNames.Buf.Size);
return TabsNames.Buf.Data + tab->NameOffset;
}
};
@@ -2239,8 +2251,8 @@ namespace ImGui
// Widgets low-level behaviors
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
- IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags);
- IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
+ IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags);
+ IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, 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 TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging
@@ -2249,9 +2261,10 @@ namespace ImGui
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); "
- template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, float power, ImGuiDragFlags flags);
- template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
- template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos);
+ template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
+ template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
+ template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiDragFlags flags);
+ template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);
// Data type helpers
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 1103167e..8096d292 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -1917,10 +1917,11 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
}
template
-static bool ClampBehaviorT(T* v, T v_min, T v_max)
+static bool ClampBehaviorT(T* v, const T* v_min, const T* v_max)
{
- if (*v < v_min) { *v = v_min; return true; }
- if (*v > v_max) { *v = v_max; return true; }
+ // Clamp, both sides are optional
+ if (v_min && *v < *v_min) { *v = *v_min; return true; }
+ if (v_max && *v > *v_max) { *v = *v_max; return true; }
return false;
}
@@ -1928,16 +1929,16 @@ bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_m
{
switch (data_type)
{
- case ImGuiDataType_S8: return ClampBehaviorT((ImS8* )p_data, *(const ImS8* )p_min, *(const ImS8* )p_max);
- case ImGuiDataType_U8: return ClampBehaviorT((ImU8* )p_data, *(const ImU8* )p_min, *(const ImU8* )p_max);
- case ImGuiDataType_S16: return ClampBehaviorT((ImS16* )p_data, *(const ImS16* )p_min, *(const ImS16* )p_max);
- case ImGuiDataType_U16: return ClampBehaviorT((ImU16* )p_data, *(const ImU16* )p_min, *(const ImU16* )p_max);
- case ImGuiDataType_S32: return ClampBehaviorT((ImS32* )p_data, *(const ImS32* )p_min, *(const ImS32* )p_max);
- case ImGuiDataType_U32: return ClampBehaviorT((ImU32* )p_data, *(const ImU32* )p_min, *(const ImU32* )p_max);
- case ImGuiDataType_S64: return ClampBehaviorT((ImS64* )p_data, *(const ImS64* )p_min, *(const ImS64* )p_max);
- case ImGuiDataType_U64: return ClampBehaviorT((ImU64* )p_data, *(const ImU64* )p_min, *(const ImU64* )p_max);
- case ImGuiDataType_Float: return ClampBehaviorT((float* )p_data, *(const float* )p_min, *(const float* )p_max);
- case ImGuiDataType_Double: return ClampBehaviorT((double*)p_data, *(const double*)p_min, *(const double*)p_max);
+ case ImGuiDataType_S8: return ClampBehaviorT((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max);
+ case ImGuiDataType_U8: return ClampBehaviorT((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max);
+ case ImGuiDataType_S16: return ClampBehaviorT((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max);
+ case ImGuiDataType_U16: return ClampBehaviorT((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max);
+ case ImGuiDataType_S32: return ClampBehaviorT((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max);
+ case ImGuiDataType_U32: return ClampBehaviorT((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max);
+ case ImGuiDataType_S64: return ClampBehaviorT((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max);
+ case ImGuiDataType_U64: return ClampBehaviorT((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max);
+ case ImGuiDataType_Float: return ClampBehaviorT((float* )p_data, (const float* )p_min, (const float* )p_max);
+ case ImGuiDataType_Double: return ClampBehaviorT((double*)p_data, (const double*)p_min, (const double*)p_max);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
@@ -2004,16 +2005,13 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type,
// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls)
template
-bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiDragFlags flags)
+bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiDragFlags flags)
{
ImGuiContext& g = *GImGui;
const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
const bool is_clamped = (v_min < v_max);
- const bool is_power = (power != 1.0f && is_decimal && is_clamped && (v_max - v_min < FLT_MAX));
- const bool is_locked = (v_min > v_max);
- if (is_locked)
- return false;
+ const bool is_logarithmic = (flags & ImGuiDragFlags_Logarithmic) && is_decimal;
// Default tweak speed
if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))
@@ -2041,12 +2039,15 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
if (axis == ImGuiAxis_Y)
adjust_delta = -adjust_delta;
+ // For logarithmic use our range is effectively 0..1 so scale the delta into that range
+ if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) // Epsilon to avoid /0
+ adjust_delta /= (float)(v_max - v_min);
+
// Clear current value on activation
// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
bool is_just_activated = g.ActiveIdIsJustActivated;
bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
- bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0));
- if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power)
+ if (is_just_activated || is_already_past_limits_and_pushing_outward)
{
g.DragCurrentAccum = 0.0f;
g.DragCurrentAccumDirty = false;
@@ -2063,13 +2064,19 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
TYPE v_cur = *v;
FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f;
- if (is_power)
+ float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true
+ const float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense)
+ if (is_logarithmic)
{
- // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range
- FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power);
- FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min));
- v_cur = v_min + (SIGNEDTYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min);
- v_old_ref_for_accum_remainder = v_old_norm_curved;
+ // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound.
+ const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 1;
+ logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision);
+
+ // Convert to parametric space, apply delta, convert back
+ float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+ float v_new_parametric = v_old_parametric + g.DragCurrentAccum;
+ v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+ v_old_ref_for_accum_remainder = v_old_parametric;
}
else
{
@@ -2077,14 +2084,16 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
}
// Round to user desired precision based on format string
- v_cur = RoundScalarWithFormatT(format, data_type, v_cur);
+ if (!(flags & ImGuiDragFlags_NoRoundToFormat))
+ v_cur = RoundScalarWithFormatT(format, data_type, v_cur);
// Preserve remainder after rounding has been applied. This also allow slow tweaking of values.
g.DragCurrentAccumDirty = false;
- if (is_power)
+ if (is_logarithmic)
{
- FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power);
- g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder);
+ // Convert to parametric space, apply delta, convert back
+ float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+ g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder);
}
else
{
@@ -2111,8 +2120,11 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
return true;
}
-bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags)
+bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags)
{
+ // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
+ IM_ASSERT((flags == 1 || (flags & ImGuiDragFlags_InvalidMask_) == 0) && "Invalid ImGuiDragFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiDragFlags_Logarithmic flags instead.");
+
ImGuiContext& g = *GImGui;
if (g.ActiveId == id)
{
@@ -2123,21 +2135,21 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
}
if (g.ActiveId != id)
return false;
- if (g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly)
+ if ((g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiDragFlags_ReadOnly))
return false;
switch (data_type)
{
- case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
- case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
- case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
- case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
- case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, power, flags);
- case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, power, flags);
- case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, power, flags);
- case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, power, flags);
- case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, power, flags);
- case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, power, flags);
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
+ case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags);
+ case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags);
+ case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags);
+ case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags);
+ case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags);
+ case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
@@ -2145,16 +2157,13 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
}
// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional.
-// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
-bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
+// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
+bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
- if (power != 1.0f)
- IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
-
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
@@ -2175,10 +2184,11 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
// Tabbing or CTRL-clicking on Drag turns it into an input box
const bool hovered = ItemHoverable(frame_bb, id);
- bool temp_input_is_active = TempInputIsActive(id);
+ const bool temp_input_allowed = (flags & ImGuiDragFlags_NoInput) == 0;
+ bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active)
{
- const bool focus_requested = FocusableItemRegister(window, id);
+ const bool focus_requested = temp_input_allowed && 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)
@@ -2187,7 +2197,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
- if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)
+ if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id))
{
temp_input_is_active = true;
FocusableItemUnregister(window);
@@ -2195,9 +2205,12 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
}
}
- // Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that..
if (temp_input_is_active)
- return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
+ {
+ // Only clamp CTRL+Click input when ImGuiDragFlags_ClampInput is set
+ const bool is_clamp_input = (flags & ImGuiDragFlags_ClampOnInput) != 0;
+ return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
+ }
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@@ -2205,7 +2218,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
// Drag behavior
- const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, power, ImGuiDragFlags_None);
+ const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags);
if (value_changed)
MarkItemEdited(id);
@@ -2221,7 +2234,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
return value_changed;
}
-bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
+bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiDragFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2238,7 +2251,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
- value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, power);
+ value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags);
PopID();
PopItemWidth();
p_data = (void*)((char*)p_data + type_size);
@@ -2256,27 +2269,28 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data
return value_changed;
}
-bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power)
+bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power);
+ return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power)
+bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power);
+ return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power)
+bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power);
+ return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power)
+bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power);
+ return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power)
+// NB: You likely want to specify the ImGuiDragFlags_ClampOnInput when using this.
+bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiDragFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2287,17 +2301,17 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu
BeginGroup();
PushMultiItemsWidths(2, CalcItemWidth());
- float min = (v_min >= v_max) ? -FLT_MAX : v_min;
- float max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
- if (min == max) { min = FLT_MAX; max = -FLT_MAX; } // Lock edit
- bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min, &max, format, power);
+ float min_min = (v_min >= v_max) ? -FLT_MAX : v_min;
+ float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
+ ImGuiDragFlags min_flags = flags | ((min_min == min_max) ? ImGuiDragFlags_ReadOnly : 0);
+ bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags);
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
- min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
- max = (v_min >= v_max) ? FLT_MAX : v_max;
- if (min == max) { min = FLT_MAX; max = -FLT_MAX; } // Lock edit
- value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &min, &max, format_max ? format_max : format, power);
+ float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
+ float max_max = (v_min >= v_max) ? FLT_MAX : v_max;
+ ImGuiDragFlags max_flags = flags | ((max_min == max_max) ? ImGuiDragFlags_ReadOnly : 0);
+ value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags);
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
@@ -2308,27 +2322,28 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu
}
// NB: v_speed is float to allow adjusting the drag speed with more precision
-bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format)
+bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format);
+ return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format)
+bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format);
+ return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format)
+bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format);
+ return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format)
+bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiDragFlags flags)
{
- return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format);
+ return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags);
}
-bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max)
+// NB: You likely want to specify the ImGuiDragFlags_ClampOnInput when using this.
+bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiDragFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2339,17 +2354,17 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
BeginGroup();
PushMultiItemsWidths(2, CalcItemWidth());
- int min = (v_min >= v_max) ? INT_MIN : v_min;
- int max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
- if (min == max) { min = INT_MAX; max = INT_MIN; } // Lock edit
- bool value_changed = DragInt("##min", v_current_min, v_speed, min, max, format);
+ int min_min = (v_min >= v_max) ? INT_MIN : v_min;
+ int min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
+ ImGuiDragFlags min_flags = flags | ((min_min == min_max) ? ImGuiDragFlags_ReadOnly : 0);
+ bool value_changed = DragInt("##min", v_current_min, v_speed, min_min, min_max, format, min_flags);
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
- min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
- max = (v_min >= v_max) ? INT_MAX : v_max;
- if (min == max) { min = INT_MAX; max = INT_MIN; } // Lock edit
- value_changed |= DragInt("##max", v_current_max, v_speed, min, max, format_max ? format_max : format);
+ int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
+ int max_max = (v_min >= v_max) ? INT_MAX : v_max;
+ ImGuiDragFlags max_flags = flags | ((max_min == max_max) ? ImGuiDragFlags_ReadOnly : 0);
+ value_changed |= DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags);
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
@@ -2360,9 +2375,40 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
return value_changed;
}
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+
+// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details.
+bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
+{
+ ImGuiDragFlags drag_flags = ImGuiDragFlags_None;
+ if (power != 1.0f)
+ {
+ IM_ASSERT(power == 1.0f && "Call function with ImGuiDragFlags_Logarithmic flags instead of using the old 'float power' function!");
+ IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
+ drag_flags |= ImGuiDragFlags_Logarithmic; // Fallback for non-asserting paths
+ }
+ return DragScalar(label, data_type, p_data, v_speed, p_min, p_max, format, drag_flags);
+}
+
+bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
+{
+ ImGuiDragFlags drag_flags = ImGuiDragFlags_None;
+ if (power != 1.0f)
+ {
+ IM_ASSERT(power == 1.0f && "Call function with ImGuiDragFlags_Logarithmic flags instead of using the old 'float power' function!");
+ IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
+ drag_flags |= ImGuiDragFlags_Logarithmic; // Fallback for non-asserting paths
+ }
+ return DragScalarN(label, data_type, p_data, components, v_speed, p_min, p_max, format, drag_flags);
+}
+
+#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+
//-------------------------------------------------------------------------
// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc.
//-------------------------------------------------------------------------
+// - ScaleRatioFromValueT<> [Internal]
+// - ScaleValueFromRatioT<> [Internal]
// - SliderBehaviorT<>() [Internal]
// - SliderBehavior() [Internal]
// - SliderScalar()
@@ -2381,42 +2427,147 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
// - VSliderInt()
//-------------------------------------------------------------------------
+// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT)
template
-float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos)
+float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
{
if (v_min == v_max)
return 0.0f;
+ IM_UNUSED(data_type);
- const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double);
const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
- if (is_power)
+ if (is_logarithmic)
{
- if (v_clamped < 0.0f)
+ bool flipped = v_max < v_min;
+
+ if (flipped) // Handle the case where the range is backwards
+ ImSwap(v_min, v_max);
+
+ // Fudge min/max to avoid getting close to log(0)
+ 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;
+
+ // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon)
+ if ((v_min == 0.0f) && (v_max < 0.0f))
+ v_min_fudged = -logarithmic_zero_epsilon;
+ else if ((v_max == 0.0f) && (v_min < 0.0f))
+ 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)
+ result = 1.0f; // Workaround for values that are in-range but above our fudge
+ else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions
{
- const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min));
- return (1.0f - ImPow(f, 1.0f / power)) * linear_zero_pos;
+ float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine)
+ float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
+ float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
+ if (v == 0.0f)
+ result = zero_point_center; // Special case for exactly zero
+ else if (v < 0.0f)
+ result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L;
+ else
+ result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R));
}
+ else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider
+ result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged));
else
- {
- const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min)));
- return linear_zero_pos + ImPow(f, 1.0f / power) * (1.0f - linear_zero_pos);
- }
+ result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged));
+
+ return flipped ? (1.0f - result) : result;
}
// Linear slider
return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min));
}
-// FIXME: Move some of the code into SliderBehavior(). Current responsibility is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc.
+// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)
+template
+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)
+ return (TYPE)0.0f;
+ const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
+
+ TYPE result;
+ 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
+ {
+ 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)));
+ else
+ result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));
+ }
+ }
+ else
+ {
+ // Linear slider
+ if (is_decimal)
+ {
+ result = ImLerp(v_min, v_max, t);
+ }
+ else
+ {
+ // 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..
+ FLOATTYPE v_new_off_f = (v_max - v_min) * t;
+ TYPE v_new_off_floor = (TYPE)(v_new_off_f);
+ TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5);
+ if (v_new_off_floor < v_new_off_round)
+ result = v_min + v_new_off_round;
+ else
+ result = v_min + v_new_off_floor;
+ }
+ }
+
+ return result;
+}
+
+// FIXME: Move more of the code into SliderBehavior()
template
-bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb)
+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)
{
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
- const bool is_power = (power != 1.0f) && is_decimal;
+ const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal;
const float grab_padding = 2.0f;
const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;
@@ -2429,19 +2580,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;
const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f;
- // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f
- float linear_zero_pos; // 0.0->1.0f
- if (is_power && v_min * v_max < 0.0f)
+ float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true
+ float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true
+ if (is_logarithmic)
{
- // Different sign
- const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f / power);
- const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f / power);
- linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0));
- }
- else
- {
- // Same sign
- linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
+ // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound.
+ const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 1;
+ logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision);
+ zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f);
}
// Process interacting with the slider
@@ -2467,87 +2613,80 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
}
else if (g.ActiveIdSource == ImGuiInputSource_Nav)
{
- const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f);
- float delta = (axis == ImGuiAxis_X) ? delta2.x : -delta2.y;
- if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
+ if (g.ActiveIdIsJustActivated)
{
- ClearActiveID();
+ g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation
+ g.SliderCurrentAccumDirty = false;
}
- else if (delta != 0.0f)
+
+ const ImVec2 input_delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f);
+ float input_delta = (axis == ImGuiAxis_X) ? input_delta2.x : -input_delta2.y;
+ if (input_delta != 0.0f)
{
- clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos);
const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0;
- if ((decimal_precision > 0) || is_power)
+ if (decimal_precision > 0)
{
- delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds
+ input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds
if (IsNavInputDown(ImGuiNavInput_TweakSlow))
- delta /= 10.0f;
+ input_delta /= 10.0f;
}
else
{
if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow))
- delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps
+ input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps
else
- delta /= 100.0f;
+ input_delta /= 100.0f;
}
if (IsNavInputDown(ImGuiNavInput_TweakFast))
- delta *= 10.0f;
- set_new_value = true;
+ input_delta *= 10.0f;
+
+ g.SliderCurrentAccum += input_delta;
+ g.SliderCurrentAccumDirty = true;
+ }
+
+ float delta = g.SliderCurrentAccum;
+ if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
+ {
+ ClearActiveID();
+ }
+ else if (g.SliderCurrentAccumDirty)
+ {
+ clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+
if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits
+ {
set_new_value = false;
+ g.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate
+ }
else
+ {
+ set_new_value = true;
+ float old_clicked_t = clicked_t;
clicked_t = ImSaturate(clicked_t + delta);
+
+ // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator
+ TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+ if (!(flags & ImGuiSliderFlags_NoRoundToFormat))
+ v_new = RoundScalarWithFormatT(format, data_type, v_new);
+ float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
+
+ if (delta > 0)
+ g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta);
+ else
+ g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta);
+ }
+
+ g.SliderCurrentAccumDirty = false;
}
}
if (set_new_value)
{
- TYPE v_new;
- if (is_power)
- {
- // Account for power curve scale on both sides of the zero
- if (clicked_t < linear_zero_pos)
- {
- // Negative: rescale to the negative range before powering
- float a = 1.0f - (clicked_t / linear_zero_pos);
- a = ImPow(a, power);
- v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a);
- }
- else
- {
- // Positive: rescale to the positive range before powering
- float a;
- if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f)
- a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos);
- else
- a = clicked_t;
- a = ImPow(a, power);
- v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a);
- }
- }
- else
- {
- // Linear slider
- if (is_decimal)
- {
- v_new = ImLerp(v_min, v_max, clicked_t);
- }
- else
- {
- // 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..
- FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t;
- TYPE v_new_off_floor = (TYPE)(v_new_off_f);
- TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5);
- if (v_new_off_floor < v_new_off_round)
- v_new = v_min + v_new_off_round;
- else
- v_new = v_min + v_new_off_floor;
- }
- }
+ TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
// Round to user desired precision based on format string
- v_new = RoundScalarWithFormatT(format, data_type, v_new);
+ if (!(flags & ImGuiSliderFlags_NoRoundToFormat))
+ v_new = RoundScalarWithFormatT(format, data_type, v_new);
// Apply result
if (*v != v_new)
@@ -2565,7 +2704,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
else
{
// Output grab position so it can be displayed by the caller
- float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos);
+ float grab_t = ScaleRatioFromValueT(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);
@@ -2581,36 +2720,39 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
// For 32-bit and larger types, slider bounds are limited to half the natural type range.
// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok.
// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders.
-bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb)
+bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
{
+ // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
+ IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
+
ImGuiContext& g = *GImGui;
- if (g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly)
+ if ((g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))
return false;
switch (data_type)
{
- case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
- case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
- case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
- case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
case ImGuiDataType_S32:
IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2);
- return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_U32:
IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2);
- return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_S64:
IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2);
- return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_U64:
IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2);
- return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_Float:
IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f);
- return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_Double:
IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f);
- return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, power, flags, out_grab_bb);
+ return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
@@ -2619,7 +2761,7 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type
// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required.
// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
-bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
+bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2646,10 +2788,11 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
// Tabbing or CTRL-clicking on Slider turns it into an input box
const bool hovered = ItemHoverable(frame_bb, id);
- bool temp_input_is_active = TempInputIsActive(id);
+ const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
+ bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active)
{
- const bool focus_requested = FocusableItemRegister(window, id);
+ const bool focus_requested = temp_input_allowed && FocusableItemRegister(window, id);
const bool clicked = (hovered && g.IO.MouseClicked[0]);
if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
{
@@ -2657,7 +2800,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
SetFocusID(id, window);
FocusWindow(window);
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
- if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)
+ if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id))
{
temp_input_is_active = true;
FocusableItemUnregister(window);
@@ -2665,9 +2808,12 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
}
}
- // Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that..
if (temp_input_is_active)
- return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
+ {
+ // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampInput is set
+ const bool is_clamp_input = (flags & ImGuiSliderFlags_ClampOnInput) != 0;
+ return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
+ }
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@@ -2676,7 +2822,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
// Slider behavior
ImRect grab_bb;
- const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_None, &grab_bb);
+ const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb);
if (value_changed)
MarkItemEdited(id);
@@ -2697,7 +2843,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
}
// Add multiple sliders on 1 line for compact edition of multiple components
-bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power)
+bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2714,7 +2860,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
- value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power);
+ value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags);
PopID();
PopItemWidth();
v = (void*)((char*)v + type_size);
@@ -2732,57 +2878,57 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
return value_changed;
}
-bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power)
+bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power);
+ return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power)
+bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power);
+ return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power)
+bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power);
+ return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power)
+bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power);
+ return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format)
+bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags)
{
if (format == NULL)
format = "%.0f deg";
float v_deg = (*v_rad) * 360.0f / (2 * IM_PI);
- bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, 1.0f);
+ bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags);
*v_rad = v_deg * (2 * IM_PI) / 360.0f;
return value_changed;
}
-bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format)
+bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format);
+ return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format)
+bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format);
+ return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format)
+bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format);
+ return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags);
}
-bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format)
+bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags)
{
- return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format);
+ return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags);
}
-bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
+bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2822,7 +2968,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
// Slider behavior
ImRect grab_bb;
- const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb);
+ const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb);
if (value_changed)
MarkItemEdited(id);
@@ -2841,16 +2987,43 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
return value_changed;
}
-bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power)
+bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags)
{
- return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power);
+ return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);
}
-bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format)
+bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags)
{
- return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format);
+ return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);
}
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+
+// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details.
+bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
+{
+ ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
+ if (power != 1.0f)
+ {
+ IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
+ slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
+ }
+ return SliderScalar(label, data_type, p_data, p_min, p_max, format, slider_flags);
+}
+
+bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power)
+{
+ ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
+ if (power != 1.0f)
+ {
+ IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
+ slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
+ }
+ return SliderScalarN(label, data_type, v, components, v_min, v_max, format, slider_flags);
+}
+
+#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+
//-------------------------------------------------------------------------
// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc.
//-------------------------------------------------------------------------
@@ -2966,20 +3139,10 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char*
return value_changed;
}
-// Note that Drag/Slider functions are currently NOT forwarding the min/max values clamping values!
+// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the
+// ImGuiDragFlags_ClampOnInput / ImGuiSliderFlags_ClampOnInput flag is set!
// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility.
// However this may not be ideal for all uses, as some user code may break on out of bound values.
-// In the future we should add flags to Slider/Drag to specify how to enforce min/max values with CTRL+Click.
-// See GitHub issues #1829 and #3209
-// In the meanwhile, you can easily "wrap" those functions to enforce clamping, using wrapper functions, e.g.
-// bool SliderFloatClamp(const char* label, float* v, float v_min, float v_max)
-// {
-// float v_backup = *v;
-// if (!SliderFloat(label, v, v_min, v_max))
-// return false;
-// *v = ImClamp(*v, v_min, v_max);
-// return v_backup != *v;
-// }
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max)
{
ImGuiContext& g = *GImGui;
@@ -3002,7 +3165,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
// Apply new value (or operations) then clamp
DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL);
- if (p_clamp_min && p_clamp_max)
+ if (p_clamp_min || p_clamp_max)
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
// Only mark as edited if new value is different
@@ -6748,15 +6911,17 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
ImGuiContext& g = *GImGui;
tab_bar->WantLayout = false;
- // Garbage collect
+ // Garbage collect by compacting list
int tab_dst_n = 0;
for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];
- if (tab->LastFrameVisible < tab_bar->PrevFrameVisible)
+ if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose)
{
- if (tab->ID == tab_bar->SelectedTabId)
- tab_bar->SelectedTabId = 0;
+ // Remove tab
+ if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; }
+ if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; }
+ if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; }
continue;
}
if (tab_dst_n != tab_src_n)
@@ -7114,7 +7279,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
arrow_col.w *= 0.5f;
PushStyleColor(ImGuiCol_Text, arrow_col);
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
- bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview);
+ bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest);
PopStyleColor(2);
ImGuiTabItem* tab_to_select = NULL;
@@ -7251,7 +7416,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
else
{
IM_ASSERT(tab->Window == NULL);
- tab->NameOffset = tab_bar->TabsNames.size();
+ tab->NameOffset = (ImS16)tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Append name _with_ the zero-terminator.
}
@@ -7450,9 +7615,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
}
// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed.
-// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem().
+// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar().
// Tabs closed by the close button will automatically be flagged to avoid this issue.
-// FIXME: We should aim to support calling SetTabItemClosed() after the tab submission (for next frame)
void ImGui::SetTabItemClosed(const char* label)
{
ImGuiContext& g = *GImGui;
@@ -7460,9 +7624,9 @@ void ImGui::SetTabItemClosed(const char* label)
if (is_within_manual_tab_bar)
{
ImGuiTabBar* tab_bar = g.CurrentTabBar;
- IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem()
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
- TabBarRemoveTab(tab_bar, tab_id);
+ if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
+ tab->WantClose = true; // Will be processed by next call to TabBarLayout()
}
else if (ImGuiWindow* window = FindWindowByName(label))
{