From c961a9eea631444b119917e730be8f77a7a5fc89 Mon Sep 17 00:00:00 2001 From: Benualdo Date: Thu, 14 Nov 2024 22:41:28 +0100 Subject: [PATCH] ImGui::CustomDragFloatN A custom version of ImGui::DragFloatN that do not return 'true' if value is modified using keyboard while editing until 'Enter' is pressed. --- .../ImGui/Extensions/ImGuiExtensions.cpp | 64 ++++++++++++++ src/editor/ImGui/Extensions/imGuiExtensions.h | 9 ++ src/editor/ImGui/Window/ImGuiWindow.cpp | 88 +++++++++---------- src/version.h | 2 +- 4 files changed, 118 insertions(+), 45 deletions(-) diff --git a/src/editor/ImGui/Extensions/ImGuiExtensions.cpp b/src/editor/ImGui/Extensions/ImGuiExtensions.cpp index 030177451..342c5bdf7 100644 --- a/src/editor/ImGui/Extensions/ImGuiExtensions.cpp +++ b/src/editor/ImGui/Extensions/ImGuiExtensions.cpp @@ -510,6 +510,7 @@ namespace ImGui g_disabledStack.push_back(_disabled); } + //-------------------------------------------------------------------------------------- void PopDisabledStyle() { @@ -521,4 +522,67 @@ namespace ImGui ApplyDisabledStyle(disabled); } } + + //-------------------------------------------------------------------------------------- + // A custom version of ImGui::DragScalarN that do not return 'true" when value is entered using keyboard + //-------------------------------------------------------------------------------------- + bool CustomDragScalarN(InteractionType & _interactionType, 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, ImGuiSliderFlags flags) + { + auto * window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + _interactionType = InteractionType::Continuous; + + ImGuiContext & g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = DataTypeGetInfo(data_type)->Size; + for (int i = 0; i < components; i++) + { + 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, flags); + + const ImGuiID id = ImGui::GetCurrentWindow()->GetID(""); + if (ImGui::TempInputIsActive(id)) + value_changed = false; + + if (ImGui::IsItemDeactivatedAfterEdit()) + { + value_changed = true; + _interactionType = InteractionType::Single; + } + + PopID(); + PopItemWidth(); + p_data = (void *)((char *)p_data + type_size); + } + PopID(); + + const char * label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; + } + + //-------------------------------------------------------------------------------------- + bool CustomDragFloat3(InteractionType & _interactionType, const char * label, float v[3], float v_speed, float v_min, float v_max, const char * format, ImGuiSliderFlags flags) + { + return CustomDragScalarN(_interactionType, label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags); + } + + //-------------------------------------------------------------------------------------- + bool CustomDragFloat4(InteractionType & _interactionType, const char * label, float v[4], float v_speed, float v_min, float v_max, const char * format, ImGuiSliderFlags flags) + { + return CustomDragScalarN(_interactionType, label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); + } } \ No newline at end of file diff --git a/src/editor/ImGui/Extensions/imGuiExtensions.h b/src/editor/ImGui/Extensions/imGuiExtensions.h index 5ec38d02e..240c541f1 100644 --- a/src/editor/ImGui/Extensions/imGuiExtensions.h +++ b/src/editor/ImGui/Extensions/imGuiExtensions.h @@ -18,6 +18,11 @@ namespace vg::renderer namespace ImGui { + vg_enum_class(InteractionType, vg::core::u8, + Single = 0, + Continuous + ); + ImVec4 getDisabledButtonColor(); ImVec4 getDisabledTextColor(); @@ -61,4 +66,8 @@ namespace ImGui void PushDisabledStyle(bool _disabled); void PopDisabledStyle(); + + bool CustomDragScalarN(InteractionType & _interactionType, const char * label, ImGuiDataType data_type, void * p_data, int components, float v_speed = 1.0f, const void * p_min = NULL, const void * p_max = NULL, const char * format = NULL, ImGuiSliderFlags flags = 0); + bool CustomDragFloat3(InteractionType & _interactionType, 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", ImGuiSliderFlags flags = 0); + bool CustomDragFloat4(InteractionType & _interactionType, 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", ImGuiSliderFlags flags = 0); } \ No newline at end of file diff --git a/src/editor/ImGui/Window/ImGuiWindow.cpp b/src/editor/ImGui/Window/ImGuiWindow.cpp index b5bd23703..065d54265 100644 --- a/src/editor/ImGui/Window/ImGuiWindow.cpp +++ b/src/editor/ImGui/Window/ImGuiWindow.cpp @@ -25,6 +25,8 @@ #include "editor/imgui/Extensions/FileDialog/ImGuiFileDialog.h" #include "ImGuiWindow.h" +#include "D:\GitHub\vimontgames\vgframework\extern\imgui\imgui_internal.h" + #if !VG_ENABLE_INLINE #include "ImGuiWindow.inl" #endif @@ -332,11 +334,6 @@ namespace vg::editor template <> struct ImGuiDataTypeInfo { static const ImGuiDataType_ type = ImGuiDataType_Float; }; - vg_enum_class(InteractionType, core::u8, - Single = 0, - Continuous - ); - template EditingState undoRedoBeforeEdit(bool & edited, PropertyContext & _propContext, IObject * _object, const IProperty * _prop, typename vectorTraits::type * temp, typename vectorTraits::type * _ptr, InteractionType _interactionType, bool _itemActive = false, bool _itemAfterEdit = false) { constexpr auto count = vectorTraits::count; @@ -460,6 +457,8 @@ namespace vg::editor if (_propContext.m_readOnly) ImGui::BeginDisabled(true); + InteractionType interactionType = InteractionType::Continuous; + if (asBool(PropertyFlags::Color & flags) && (count == 3 || count == 4)) { ImGuiColorEditFlags colorEditFlags = 0; @@ -481,15 +480,15 @@ namespace vg::editor else { if (asBool(PropertyFlags::HasRange & flags)) - edited = ImGui::DragScalarN(ImGuiWindow::getPropertyLabel(_label).c_str(), ImGuiDataTypeInfo::type, &temp, count, dragSpeed, &minRange, &maxRange, editFormat); + edited = CustomDragScalarN(interactionType, ImGuiWindow::getPropertyLabel(_label).c_str(), ImGuiDataTypeInfo::type, &temp, count, dragSpeed, &minRange, &maxRange, editFormat, ImGuiSliderFlags_NoRoundToFormat); else - edited = ImGui::DragScalarN(ImGuiWindow::getPropertyLabel(_label).c_str(), ImGuiDataTypeInfo::type, &temp, count, dragSpeed, nullptr, nullptr, editFormat); + edited = CustomDragScalarN(interactionType, ImGuiWindow::getPropertyLabel(_label).c_str(), ImGuiDataTypeInfo::type, &temp, count, dragSpeed, nullptr, nullptr, editFormat, ImGuiSliderFlags_NoRoundToFormat); } if (_propContext.m_readOnly) edited = false; - EditingState editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (S*)&temp[0], _ptr, InteractionType::Continuous); + EditingState editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (S*)&temp[0], _ptr, interactionType); if (_propContext.m_readOnly) ImGui::EndDisabled(); @@ -2713,6 +2712,7 @@ namespace vg::editor ImGui::BeginDisabled(); bool itemActive = false, itemAfterEdit = false; + InteractionType interactionType = InteractionType::Continuous; //if (useTRS) { @@ -2731,19 +2731,19 @@ namespace vg::editor float prevRot[3] = { rotation[0], rotation[1], rotation[2] }; float prevScale[3] = { scale[0], scale[1], scale[2] }; - edited |= ImGui::DragFloat3(getPropertyLabel("T").c_str(), (float *)&translation, getDragSpeedFloat(_prop) * 90.0f/8.0f, -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - itemActive = ImGui::IsItemActive(); - itemAfterEdit = ImGui::IsItemDeactivatedAfterEdit(); + edited |= CustomDragFloat3(interactionType, getPropertyLabel("T").c_str(), (float *)&translation, getDragSpeedFloat(_prop) * 90.0f/8.0f, -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + itemActive = ImGui::IsItemActive() || InteractionType::Single == interactionType; + itemAfterEdit = ImGui::IsItemDeactivatedAfterEdit() || InteractionType::Single == interactionType; drawPropertyLabel(_propContext, TLabel.c_str(), "Represents the translation part of the matrix"); - edited |= ImGui::DragFloat3(getPropertyLabel("R").c_str(), (float *)&rotation, getDragSpeedFloat(_prop) * 90.0f / 8.0f, -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - itemActive |= ImGui::IsItemActive(); - itemAfterEdit |= ImGui::IsItemDeactivatedAfterEdit(); + edited |= CustomDragFloat3(interactionType, getPropertyLabel("R").c_str(), (float *)&rotation, getDragSpeedFloat(_prop) * 90.0f / 8.0f, -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + itemActive |= ImGui::IsItemActive() || InteractionType::Single == interactionType; + itemAfterEdit |= ImGui::IsItemDeactivatedAfterEdit() || InteractionType::Single == interactionType; drawPropertyLabel(_propContext, RLabel.c_str(), "Represents the rotation part of the matrix"); - edited |= ImGui::DragFloat3(getPropertyLabel("S").c_str(), (float *)&scale, getDragSpeedFloat(_prop) * 90.0f / 8.0f, 0.01f, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - itemActive |= ImGui::IsItemActive(); - itemAfterEdit |= ImGui::IsItemDeactivatedAfterEdit(); + edited |= CustomDragFloat3(interactionType, getPropertyLabel("S").c_str(), (float *)&scale, getDragSpeedFloat(_prop) * 90.0f / 8.0f, 0.01f, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + itemActive |= ImGui::IsItemActive() || InteractionType::Single == interactionType; + itemAfterEdit |= ImGui::IsItemDeactivatedAfterEdit() || InteractionType::Single == interactionType; drawPropertyLabel(_propContext, SLabel.c_str(), "Represents the scale part of the matrix"); if (edited) @@ -2817,35 +2817,35 @@ namespace vg::editor } if (EditingState::Unknown == editingState) - editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, InteractionType::Continuous, itemActive, itemAfterEdit); + editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, interactionType, itemActive, itemAfterEdit); //else - if (false && ImGui::TreeNode(getObjectLabel("(float4x4) " + (string)displayName, _propContext.m_originalProp).c_str())) - { - ImGui::Spacing(); - - edited |= ImGui::DragFloat4(getPropertyLabel("I").c_str(), (float *)&temp[0], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - if (EditingState::Unknown == editingState) - editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, InteractionType::Continuous); - drawPropertyLabel(_propContext, LabelI.c_str(), "Represents the x-axis in the transformed space"); - - edited |= ImGui::DragFloat4(getPropertyLabel("J").c_str(), (float *)&temp[4], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - if (EditingState::Unknown == editingState) - editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, InteractionType::Continuous); - drawPropertyLabel(_propContext, LabelJ.c_str(), "Represents the y-axis in the transformed space"); - - edited |= ImGui::DragFloat4(getPropertyLabel("K").c_str(), (float *)&temp[8], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - if (EditingState::Unknown == editingState) - editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, InteractionType::Continuous); - drawPropertyLabel(_propContext, LabelK.c_str(), "Represents the z-axis in the transformed space"); - - edited |= ImGui::DragFloat4(getPropertyLabel("T").c_str(), (float *)&temp[12], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; - if (EditingState::Unknown == editingState) - editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, InteractionType::Continuous); - drawPropertyLabel(_propContext, LabelT.c_str(), "Represents the translation component"); - - ImGui::TreePop(); - } + //if (false && ImGui::TreeNode(getObjectLabel("(float4x4) " + (string)displayName, _propContext.m_originalProp).c_str())) + //{ + // ImGui::Spacing(); + // + // edited |= ImGui::CustomDragFloat4(interactionType, getPropertyLabel("I").c_str(), (float *)&temp[0], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + // if (EditingState::Unknown == editingState || InteractionType::Single == interactionType) + // editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, interactionType); + // drawPropertyLabel(_propContext, LabelI.c_str(), "Represents the x-axis in the transformed space"); + // + // edited |= ImGui::CustomDragFloat4(interactionType, getPropertyLabel("J").c_str(), (float *)&temp[4], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + // if (EditingState::Unknown == editingState || InteractionType::Single == interactionType) + // editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, interactionType); + // drawPropertyLabel(_propContext, LabelJ.c_str(), "Represents the y-axis in the transformed space"); + // + // edited |= ImGui::CustomDragFloat4(interactionType, getPropertyLabel("K").c_str(), (float *)&temp[8], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + // if (EditingState::Unknown == editingState || InteractionType::Single == interactionType) + // editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, interactionType); + // drawPropertyLabel(_propContext, LabelK.c_str(), "Represents the z-axis in the transformed space"); + // + // edited |= ImGui::CustomDragFloat4(interactionType, getPropertyLabel("T").c_str(), (float *)&temp[12], getDragSpeedFloat(_prop), -style::range::maxFloat, style::range::maxFloat, g_editFloatFormat) && !_propContext.m_readOnly; + // if (EditingState::Unknown == editingState || InteractionType::Single == interactionType) + // editingState = undoRedoBeforeEdit(edited, _propContext, _object, _prop, (float *)&temp[0], pFloat, interactionType); + // drawPropertyLabel(_propContext, LabelT.c_str(), "Represents the translation component"); + // + // ImGui::TreePop(); + //} if (_propContext.m_readOnly) ImGui::EndDisabled(); diff --git a/src/version.h b/src/version.h index b881e211b..28cabafda 100644 --- a/src/version.h +++ b/src/version.h @@ -2,4 +2,4 @@ #define VG_FRAMEWORK_VERSION_MAJOR 0 #define VG_FRAMEWORK_VERSION_MINOR 42 -#define VG_FRAMEWORK_VERSION_PATCH 1 \ No newline at end of file +#define VG_FRAMEWORK_VERSION_PATCH 2 \ No newline at end of file