Merge branch 'master' into docking

# Conflicts:
#	imgui.cpp
#	imgui_demo.cpp
#	imgui_internal.h
This commit is contained in:
omar 2020-05-07 22:13:47 +02:00
commit 582f4db59b
9 changed files with 1114 additions and 587 deletions

View File

@ -119,11 +119,13 @@ Other Changes:
Set to 0.0f (default) to always make a close button appear on hover (same as Chrome, VS).
Set to FLT_MAX to only display a close button when selected (merely hovering is not enough).
Set to an intermediary value to toggle behavior based on width (same as Firefox).
- Metrics: Added a "Settings" section with some details about persistent ini settings.
- Backends: Win32: Support for #define NOGDI, won't try to call GetDeviceCaps(). (#3137, #2327)
- Backends: Win32: Fix _WIN32_WINNT < 0x0600 (MinGW defaults to 0x502 == Windows 2003). (#3183)
- Backends: OpenGL: Fixed handling of GL 4.5+ glClipControl(GL_UPPER_LEFT) by inverting the
projection matrix top and bottom values. (#3143, #3146) [@u3shit]
- Backends: Vulkan: Fixed error in if initial frame has no vertices. (#3177)
- Backends: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData
- Backends: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData
structure didn't have any vertices. (#2697) [@kudaba]
- Drag and Drop: Fixed unintended fallback "..." tooltip display during drag operation when
drag source uses _SourceNoPreviewTooltip flags. (#3160) [@rokups]

View File

@ -194,7 +194,7 @@ Ongoing Dear ImGui development is financially supported by users and private spo
- [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui/)
*Double-chocolate and Salty caramel sponsors*
- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [DotEmu](http://www.dotemu.com), [Framefield](http://framefield.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/)
- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/)
From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors).

View File

@ -26,7 +26,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- window: GetWindowSize() returns (0,0) when not calculated? (#1045)
- window: investigate better auto-positioning for new windows.
- window: top most window flag? (#2574)
- window: the size_on_first_use path of Begin() can probably be removed
- window/size: manually triggered auto-fit (double-click on grip) shouldn't resize window down to viewport size?
- window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false.
- window/child: background options for child windows, border option (disable rounding).

View File

@ -445,7 +445,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp };
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
@ -491,7 +491,9 @@ void ImGui_ImplWin32_EnableDpiAwareness()
return;
}
}
SetProcessDPIAware();
#if _WIN32_WINNT >= 0x0600
::SetProcessDPIAware();
#endif
}
#if defined(_MSC_VER) && !defined(NOGDI)

176
imgui.cpp
View File

@ -4,7 +4,7 @@
// Help:
// - Read FAQ at http://dearimgui.org/faq
// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. All applications in examples/ are doing that.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
// Read imgui.cpp for details, links and comments.
// Resources:
@ -923,13 +923,15 @@ static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For u
static void SetCurrentWindow(ImGuiWindow* window);
static void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size);
static void FindHoveredWindow();
static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
// Settings
static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
@ -4130,6 +4132,8 @@ void ImGui::Initialize(ImGuiContext* context)
ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "Window";
ini_handler.TypeHash = ImHashStr("Window");
ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
@ -5200,7 +5204,23 @@ ImGuiWindow* ImGui::FindWindowByName(const char* name)
return FindWindowByID(id);
}
static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
{
if (settings->ViewportId)
{
window->ViewportId = settings->ViewportId;
window->ViewportPos = ImVec2(settings->ViewportPos.x, settings->ViewportPos.y);
}
window->Pos = ImFloor(ImVec2(settings->Pos.x + window->ViewportPos.x, settings->Pos.y + window->ViewportPos.y));
if (settings->Size.x > 0 && settings->Size.y > 0)
window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
window->Collapsed = settings->Collapsed;
window->DockId = settings->DockId;
window->DockOrder = settings->DockOrder;
}
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
//IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
@ -5221,23 +5241,9 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
// Retrieve settings from .ini file
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
if (settings->ViewportId)
{
window->ViewportId = settings->ViewportId;
window->ViewportPos = ImVec2(settings->ViewportPos.x, settings->ViewportPos.y);
}
else
{
window->ViewportPos = main_viewport->Pos;
}
window->Pos = ImVec2(settings->Pos.x + window->ViewportPos.x, settings->Pos.y + window->ViewportPos.y);
window->Collapsed = settings->Collapsed;
if (settings->Size.x > 0 && settings->Size.y > 0)
size = ImVec2(settings->Size.x, settings->Size.y);
window->DockId = settings->DockId;
window->DockOrder = settings->DockOrder;
window->ViewportPos = main_viewport->Pos;
ApplyWindowSettings(window, settings);
}
window->Size = window->SizeFull = ImFloor(size);
window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
@ -5861,10 +5867,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImGuiWindow* window = FindWindowByName(name);
const bool window_just_created = (window == NULL);
if (window_just_created)
{
ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
window = CreateNewWindow(name, size_on_first_use, flags);
}
window = CreateNewWindow(name, flags);
// Automatically disable manual moving/resizing when NoInputs is set
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
@ -7306,6 +7309,7 @@ ImVec2 ImGui::GetFontTexUvWhitePixel()
void ImGui::SetWindowFontScale(float scale)
{
IM_ASSERT(scale > 0.0f);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->FontWindowScale = scale;
@ -7557,6 +7561,7 @@ static void ImGui::ErrorCheckEndFrameSanityChecks()
ImGuiContext& g = *GImGui;
// Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
// One possible reason leading to this assert is that your back-ends update inputs _AFTER_ NewFrame().
const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags();
IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
IM_UNUSED(expected_key_mod_flags);
@ -10372,6 +10377,19 @@ void ImGui::LogButtons()
//-----------------------------------------------------------------------------
// [SECTION] SETTINGS
//-----------------------------------------------------------------------------
// - UpdateSettings() [Internal]
// - MarkIniSettingsDirty() [Internal]
// - CreateNewWindowSettings() [Internal]
// - FindWindowSettings() [Internal]
// - FindOrCreateWindowSettings() [Internal]
// - FindSettingsHandler() [Internal]
// - ClearIniSettings() [Internal]
// - LoadIniSettingsFromDisk()
// - LoadIniSettingsFromMemory()
// - SaveIniSettingsToDisk()
// - SaveIniSettingsToMemory()
// - WindowSettingsHandler_***() [Internal]
//-----------------------------------------------------------------------------
// Called by NewFrame()
void ImGui::UpdateSettings()
@ -10454,16 +10472,6 @@ ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
return CreateNewWindowSettings(name);
}
void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
{
size_t file_data_size = 0;
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
IM_FREE(file_data);
}
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
{
ImGuiContext& g = *GImGui;
@ -10474,21 +10482,42 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
return NULL;
}
void ImGui::ClearIniSettings()
{
ImGuiContext& g = *GImGui;
g.SettingsIniData.clear();
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].ClearAllFn)
g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
}
void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
{
size_t file_data_size = 0;
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
if (!file_data)
return;
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
IM_FREE(file_data);
}
// Zero-tolerance, no error reporting, cheap .ini parsing
void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.Initialized);
IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
//IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
//IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
// For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
if (ini_size == 0)
ini_size = strlen(ini_data);
char* buf = (char*)IM_ALLOC(ini_size + 1);
char* buf_end = buf + ini_size;
g.SettingsIniData.Buf.resize((int)ini_size + 1);
char* const buf = g.SettingsIniData.Buf.Data;
char* const buf_end = buf + ini_size;
memcpy(buf, ini_data, ini_size);
buf[ini_size] = 0;
buf_end[0] = 0;
void* entry_data = NULL;
ImGuiSettingsHandler* entry_handler = NULL;
@ -10526,8 +10555,16 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
}
}
IM_FREE(buf);
g.SettingsLoaded = true;
// [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
memcpy(buf, ini_data, ini_size);
// Call post-read handlers
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].ApplyAllFn)
g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
DockContextOnLoadSettings(&g);
}
@ -10564,11 +10601,33 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
return g.SettingsIniData.c_str();
}
static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{
ImGuiContext& g = *ctx;
for (int i = 0; i != g.Windows.Size; i++)
g.Windows[i]->SettingsOffset = -1;
g.SettingsWindows.clear();
}
// Apply to existing windows (if any)
static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{
ImGuiContext& g = *ctx;
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (settings->WantApply)
{
if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
ApplyWindowSettings(window, settings);
settings->WantApply = false;
}
}
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{
ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name));
if (!settings)
settings = ImGui::CreateNewWindowSettings(name);
settings->WantApply = true;
return (void*)settings;
}
@ -15426,6 +15485,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::TreePop();
}
static void NodeWindowSettings(ImGuiWindowSettings* settings)
{
ImGui::Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
}
static void NodeViewport(ImGuiViewportP* viewport)
{
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
@ -15675,6 +15740,41 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
#endif // #define IMGUI_HAS_DOCK
// Settings
if (ImGui::TreeNode("Settings"))
{
if (ImGui::SmallButton("Clear"))
ImGui::ClearIniSettings();
ImGui::SameLine();
if (ImGui::SmallButton("Save to disk"))
ImGui::SaveIniSettingsToDisk(g.IO.IniFilename);
ImGui::SameLine();
if (g.IO.IniFilename)
ImGui::Text("\"%s\"", g.IO.IniFilename);
else
ImGui::TextUnformatted("<NULL>");
ImGui::Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
if (ImGui::TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
{
for (int n = 0; n < g.SettingsHandlers.Size; n++)
ImGui::TextUnformatted(g.SettingsHandlers[n].TypeName);
ImGui::TreePop();
}
if (ImGui::TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
{
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
Funcs::NodeWindowSettings(settings);
ImGui::TreePop();
}
if (ImGui::TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
{
char* buf = (char*)(void*)(g.SettingsIniData.Buf.Data ? g.SettingsIniData.Buf.Data : "");
ImGui::InputTextMultiline("##Ini", buf, g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, 0.0f), ImGuiInputTextFlags_ReadOnly);
ImGui::TreePop();
}
ImGui::TreePop();
}
// Misc Details
if (ImGui::TreeNode("Internal state"))
{

View File

@ -4,7 +4,7 @@
// Help:
// - Read FAQ at http://dearimgui.org/faq
// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. All applications in examples/ are doing that.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
// Read imgui.cpp for details, links and comments.
// Resources:

File diff suppressed because it is too large Load Diff

View File

@ -730,6 +730,11 @@ struct IMGUI_API ImRect
bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
};
struct ImGuiDataTypeTempStorage
{
ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT
};
// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
struct ImGuiDataTypeInfo
{
@ -839,8 +844,9 @@ struct ImGuiWindowSettings
ImGuiID ClassId; // ID of window class if specified
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
bool Collapsed;
bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
ImGuiWindowSettings() { ID = 0; Pos = Size = ViewportPos = ImVec2ih(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = false; }
ImGuiWindowSettings() { ID = 0; Pos = Size = ViewportPos = ImVec2ih(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = WantApply = false; }
char* GetName() { return (char*)(this + 1); }
};
@ -848,6 +854,8 @@ struct ImGuiSettingsHandler
{
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
ImGuiID TypeHash; // == ImHashStr(TypeName)
void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data
void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order)
void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
@ -1924,6 +1932,7 @@ namespace ImGui
// Settings
IMGUI_API void MarkIniSettingsDirty();
IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window);
IMGUI_API void ClearIniSettings();
IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name);
IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id);
IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name);
@ -2153,11 +2162,12 @@ namespace ImGui
IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);
IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2);
IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format);
IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max);
// InputText
IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format);
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active

View File

@ -1676,6 +1676,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
// - DataTypeFormatString()
// - DataTypeApplyOp()
// - DataTypeApplyOpFromText()
// - DataTypeClamp()
// - GetMinimumStepAtDecimalPrecision
// - RoundScalarWithFormat<>()
//-------------------------------------------------------------------------
@ -1827,11 +1828,9 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
return false;
// Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all.
IM_ASSERT(data_type < ImGuiDataType_COUNT);
int data_backup[2];
const ImGuiDataTypeInfo* type_info = ImGui::DataTypeGetInfo(data_type);
IM_ASSERT(type_info->Size <= sizeof(data_backup));
memcpy(data_backup, p_data, type_info->Size);
const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);
ImGuiDataTypeTempStorage data_backup;
memcpy(&data_backup, p_data, type_info->Size);
if (format == NULL)
format = type_info->ScanFmt;
@ -1903,7 +1902,35 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
IM_ASSERT(0);
}
return memcmp(data_backup, p_data, type_info->Size) != 0;
return memcmp(&data_backup, p_data, type_info->Size) != 0;
}
template<typename T>
static bool ClampBehaviorT(T* v, T v_min, T v_max)
{
if (*v < v_min) { *v = v_min; return true; }
if (*v > v_max) { *v = v_max; return true; }
return false;
}
bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max)
{
switch (data_type)
{
case ImGuiDataType_S8: return ClampBehaviorT<ImS8 >((ImS8* )p_data, *(const ImS8* )p_min, *(const ImS8* )p_max);
case ImGuiDataType_U8: return ClampBehaviorT<ImU8 >((ImU8* )p_data, *(const ImU8* )p_min, *(const ImU8* )p_max);
case ImGuiDataType_S16: return ClampBehaviorT<ImS16 >((ImS16* )p_data, *(const ImS16* )p_min, *(const ImS16* )p_max);
case ImGuiDataType_U16: return ClampBehaviorT<ImU16 >((ImU16* )p_data, *(const ImU16* )p_min, *(const ImU16* )p_max);
case ImGuiDataType_S32: return ClampBehaviorT<ImS32 >((ImS32* )p_data, *(const ImS32* )p_min, *(const ImS32* )p_max);
case ImGuiDataType_U32: return ClampBehaviorT<ImU32 >((ImU32* )p_data, *(const ImU32* )p_min, *(const ImU32* )p_max);
case ImGuiDataType_S64: return ClampBehaviorT<ImS64 >((ImS64* )p_data, *(const ImS64* )p_min, *(const ImS64* )p_max);
case ImGuiDataType_U64: return ClampBehaviorT<ImU64 >((ImU64* )p_data, *(const ImU64* )p_min, *(const ImU64* )p_max);
case ImGuiDataType_Float: return ClampBehaviorT<float >((float* )p_data, *(const float* )p_min, *(const float* )p_max);
case ImGuiDataType_Double: return ClampBehaviorT<double>((double*)p_data, *(const double*)p_min, *(const double*)p_max);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
return false;
}
static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
@ -2155,8 +2182,10 @@ 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 || temp_input_start)
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@ -2606,8 +2635,10 @@ 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 || temp_input_start)
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);
return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@ -2906,7 +2937,21 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char*
return value_changed;
}
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format)
// Note that Drag/Slider functions are currently NOT forwarding the min/max values clamping values!
// 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;
@ -2918,10 +2963,21 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited;
flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
bool value_changed = TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags);
if (value_changed)
bool value_changed = false;
if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags))
{
value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL);
// Backup old value
size_t data_type_size = DataTypeGetInfo(data_type)->Size;
ImGuiDataTypeTempStorage data_backup;
memcpy(&data_backup, p_data, data_type_size);
// 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)
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
// Only mark as edited if new value is different
value_changed = memcmp(&data_type, p_data, data_type_size) != 0;
if (value_changed)
MarkItemEdited(id);
}
@ -3474,6 +3530,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (window->SkipItems)
return false;
IM_ASSERT(buf != NULL && buf_size >= 0);
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)