From d6d43b9d017080e25ba72601e2f6e9f42f191d9e Mon Sep 17 00:00:00 2001 From: R2DLiu Date: Sat, 11 Jul 2020 18:56:55 -0400 Subject: [PATCH] Move out of externals into osd --- Externals/imgui/imgui.h | 1 - Externals/imgui/imgui_internal.h | 1 - Externals/imgui/imgui_widgets.cpp | 183 ------------------ Source/Core/VideoCommon/OnScreenDisplay.cpp | 204 ++++++++++++++++++-- 4 files changed, 192 insertions(+), 197 deletions(-) diff --git a/Externals/imgui/imgui.h b/Externals/imgui/imgui.h index 18eb829c7b..1164839abc 100644 --- a/Externals/imgui/imgui.h +++ b/Externals/imgui/imgui.h @@ -449,7 +449,6 @@ namespace ImGui 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* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool SliderCustom(const char* label, ImVec4 color, int* v, int v_min, int v_max, float power, const char* format = "%d"); // Widgets: Input with Keyboard // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. diff --git a/Externals/imgui/imgui_internal.h b/Externals/imgui/imgui_internal.h index 2ca301659b..9107cfeaff 100644 --- a/Externals/imgui/imgui_internal.h +++ b/Externals/imgui/imgui_internal.h @@ -1543,7 +1543,6 @@ namespace ImGui 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* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags); IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); - IMGUI_API bool SliderCustomBehavior(const ImRect& frame_bb, ImGuiID id, int* v, int v_min, int v_max, float power, ImGuiSliderFlags flags, ImVec4 color, ImVec2 valuesize, const char* label, char* value); 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 SetNextTreeNodeOpened() data, if any. May return true when logging diff --git a/Externals/imgui/imgui_widgets.cpp b/Externals/imgui/imgui_widgets.cpp index cf7b9b4762..d1ecf3ba99 100644 --- a/Externals/imgui/imgui_widgets.cpp +++ b/Externals/imgui/imgui_widgets.cpp @@ -2414,132 +2414,6 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type return false; } -bool ImGui::SliderCustomBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v_max, float power, ImGuiSliderFlags flags, ImVec4 color, ImVec2 valuesize, const char* label, char* value) -{ - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - ImGuiWindow* window = GetCurrentWindow(); - const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_decimal = false; // TODO handle other types - const bool is_power = (power != 1.0f) && is_decimal; - - const float grab_padding = 2.0f; - const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; - float grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); - int v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); - if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows - grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit - grab_sz = ImMin(grab_sz, slider_sz); - const float slider_usable_sz = slider_sz - grab_sz; - const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; - const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; - - float linear_zero_pos = 0.0f; - if (is_power && v_min * v_max < 0.0f) - { - const float linear_dist_min_to_0 = ImPow(v_min >= 0 ? (float)v_min : -(float)v_min, (float)1.0f / power); - const float linear_dist_max_to_0 = ImPow(v_max >= 0 ? (float)v_max : -(float)v_max, (float)1.0f / power); - linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); - } - else - { - linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; - } - - const bool isDown = g.IO.MouseDown[0]; - bool value_changed = false; - bool isActive = g.ActiveId == id; - const bool hovered = ItemHoverable(bb, id); - - if (!isDown && isActive) - ClearActiveID(); - - // Calculate mouse position if hovered - int new_value = 0; - if (hovered || isDown) { - const float mouse_abs_pos = g.IO.MousePos[axis]; - float clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; - if (axis == ImGuiAxis_Y) - clicked_t = 1.0f - clicked_t; - - - if (is_power) - { - if (clicked_t < linear_zero_pos) - { - float a = 1.0f - (clicked_t / linear_zero_pos); - a = ImPow(a, power); - new_value = ImLerp(ImMin(v_max, 0), v_min, a); - } - else - { - 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); - new_value = ImLerp(ImMax(v_min, 0), v_max, a); - } - } - else - { - new_value = ImLerp(v_min, v_max, clicked_t); - } - - // Only change value if left mouse button is actually down - if (*v != new_value && isDown) - { - *v = new_value; - value_changed = true; - } - } - - float new_grab_t = SliderCalcRatioFromValueT(ImGuiDataType_S32, new_value, v_min, v_max, power, linear_zero_pos); - float curr_grab_t = SliderCalcRatioFromValueT(ImGuiDataType_S32, *v, v_min, v_max, power, linear_zero_pos); - - if (axis == ImGuiAxis_Y) { - new_grab_t = 1.0f - new_grab_t; - curr_grab_t = 1.0f - curr_grab_t; - } - const float new_grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, new_grab_t); - const float curr_grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, curr_grab_t); - ImRect new_grab_bb; - ImRect curr_grab_bb; - if (axis == ImGuiAxis_X) { - new_grab_bb = ImRect(ImVec2(new_grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding), ImVec2(new_grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding)); - curr_grab_bb = ImRect(ImVec2(curr_grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding), ImVec2(curr_grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding)); - } - else - { - new_grab_bb = ImRect(ImVec2(bb.Min.x + grab_padding, new_grab_pos - grab_sz * 0.5f), ImVec2(bb.Max.x - grab_padding, new_grab_pos + grab_sz * 0.5f)); - curr_grab_bb = ImRect(ImVec2(bb.Min.x + grab_padding, curr_grab_pos - grab_sz * 0.5f), ImVec2(bb.Max.x - grab_padding, curr_grab_pos + grab_sz * 0.5f)); - } - // Draw all the things - - // Grey background line - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(bb.Max.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 0.5f)), 4); - - // Whiter, more opaque line up to mouse position - if (hovered) - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(new_grab_bb.Min.x + grab_padding * 2, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)), 4); - - if (isDown) { - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(new_grab_bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.00f)), 4); - window->DrawList->AddCircleFilled(ImVec2(new_grab_bb.Min.x + 6, new_grab_bb.Min.y + ((new_grab_bb.Max.y - new_grab_bb.Min.y) / 2)), 8, ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f))); - float width = (valuesize.x + 2 * 2.f); //width = (textWidth + 2 * padding) - window->DrawList->AddText(ImVec2(new_grab_bb.GetCenter().x - valuesize.x / 2, bb.Min.y), ImColor(255, 255, 255), value, label); - } - - if (!isDown) - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(curr_grab_bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f)), 4); - - - //window->DrawList->AddRectFilled(ImVec2(grab_bb.Min.x, bb.Min.y + 2), ImVec2(grab_bb.Max.x + valuesize.x, bb.Min.y + 14), ColorConvertFloat4ToU32(ImVec4(0.21f, 0.20f, 0.21f, 1.00f)), 3); - - return value_changed; -} - bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); @@ -2646,63 +2520,6 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i return value_changed; } -// TODO: this really should be templated but I'm lazy -bool ImGui::SliderCustom(const char* label, ImVec4 color, int* v, int v_min, int v_max, float power, const char* format) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); - const float w = CalcItemWidth(); - - const ImVec2 label_size = CalcTextSize(label, NULL, true) * 2.7; - const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 0.5f)); - const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - - if (!ItemAdd(total_bb, id)) - { - ItemSize(total_bb, style.FramePadding.y); - return false; - } - - const bool hovered = ItemHoverable(frame_bb, id); - if (hovered) - SetHoveredID(id); - - if (!format) - format = "%d"; - - bool start_text_input = false; - const bool tab_focus_requested = FocusableItemRegister(window, g.ActiveId == id); - if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) - { - SetActiveID(id, window); - FocusWindow(window); - - if (tab_focus_requested || g.IO.KeyCtrl) - { - start_text_input = true; - g.ScalarAsInputTextId = 0; - } - } - if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) - return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_S32, v, format); - - ItemSize(total_bb, style.FramePadding.y); - - char value_buf[64]; - const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); - const bool value_changed = SliderCustomBehavior(frame_bb, id, v, v_min, v_max, power, ImGuiSliderFlags_None, color, CalcTextSize(value_buf, NULL, true), value_buf_end, value_buf); - - if (label_size.x > 0.0f) - RenderText(ImVec2(frame_bb.Min.x + style.ItemInnerSpacing.x, frame_bb.Min.y + 25), label); - - return value_changed; -} - bool ImGui::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); diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index 9a8f8c6f8f..49db1f62e5 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -17,6 +17,11 @@ #include "Common/Timer.h" #include "Core/ConfigManager.h" +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" namespace OSD { @@ -37,7 +42,7 @@ struct Message }; static std::multimap s_messages; static std::mutex s_messages_mutex; -static int value = 0; +static int frame = 0; static ImVec4 RGBAToImVec4(const u32 rgba) { @@ -140,27 +145,202 @@ void DrawSlippiPlaybackControls() const float alpha = 0.5f; ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); + if (ImGui::Begin(window_name.c_str(), nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { - if (ImGui::Button("start")) { - INFO_LOG(SLIPPI, "pressed button!"); - }; - if (ImGui::Button("stop")) { - INFO_LOG(SLIPPI, "pressed button!"); - }; + //if (ImGui::Button("start")) { + // INFO_LOG(SLIPPI, "pressed button!"); + //}; + //if (ImGui::Button("stop")) { + // INFO_LOG(SLIPPI, "pressed button!"); + //}; ImGui::PushItemWidth(ImGui::GetWindowWidth()); - ImGui::SliderCustom("test", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), &value, 0, 8000, 1.0); - ImGui::SetWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, std::min(static_cast(50.0), ImGui::GetWindowHeight()))); - ImGui::SetWindowPos( - ImVec2(0, ImGui::GetIO().DisplaySize.y - ImGui::GetWindowHeight()), - true); + ImGui::Dummy(ImVec2(0.0f, ImGui::GetWindowHeight() - 50)); + ImGui::SliderCustom("test", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), &frame, 0, 8000, 1.0); } ImGui::End(); ImGui::PopStyleVar(); } + +bool SliderCustomBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v_max, float power, ImGuiSliderFlags flags, ImVec4 color, ImVec2 valuesize, const char* label, char* value) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_decimal = false; // TODO handle other types + const bool is_power = (power != 1.0f) && is_decimal; + + const float slider_sz = (bb.Max[axis] - bb.Min[axis]); + const float slider_usable_pos_min = bb.Min[axis]; + const float slider_usable_pos_max = bb.Max[axis]; + + float linear_zero_pos = 0.0f; + if (is_power && v_min * v_max < 0.0f) + { + const float linear_dist_min_to_0 = ImPow(v_min >= 0 ? (float)v_min : -(float)v_min, (float)1.0f / power); + const float linear_dist_max_to_0 = ImPow(v_max >= 0 ? (float)v_max : -(float)v_max, (float)1.0f / power); + linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); + } + else + { + linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; + } + + const bool isDown = g.IO.MouseDown[0]; + bool value_changed = false; + bool isActive = g.ActiveId == id; + const bool hovered = ImGui::ItemHoverable(bb, id); + + if (!isDown && isActive) + ImGui::ClearActiveID(); + + // Calculate mouse position if hovered + int new_value = 0; + if (hovered || isDown) { + const float mouse_abs_pos = g.IO.MousePos[axis]; + float clicked_t = (slider_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_sz, 0.0f, 1.0f) : 0.0f; + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + + + if (is_power) + { + if (clicked_t < linear_zero_pos) + { + float a = 1.0f - (clicked_t / linear_zero_pos); + a = ImPow(a, power); + new_value = ImLerp(ImMin(v_max, 0), v_min, a); + } + else + { + 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); + new_value = ImLerp(ImMax(v_min, 0), v_max, a); + } + } + else + { + new_value = ImLerp(v_min, v_max, clicked_t); + } + + // Only change value if left mouse button is actually down + if (*v != new_value && isDown && hovered) + { + *v = new_value; + value_changed = true; + } + } + + float new_grab_t = ImGui::SliderCalcRatioFromValueT(ImGuiDataType_S32, new_value, v_min, v_max, power, linear_zero_pos); + float curr_grab_t = ImGui::SliderCalcRatioFromValueT(ImGuiDataType_S32, *v, v_min, v_max, power, linear_zero_pos); + + if (axis == ImGuiAxis_Y) { + new_grab_t = 1.0f - new_grab_t; + curr_grab_t = 1.0f - curr_grab_t; + } + const float new_grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, new_grab_t); + const float curr_grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, curr_grab_t); + ImRect new_grab_bb; + ImRect curr_grab_bb; + if (axis == ImGuiAxis_X) { + new_grab_bb = ImRect(ImVec2(new_grab_pos, bb.Min.y), ImVec2(new_grab_pos * 0.5f, bb.Max.y)); + curr_grab_bb = ImRect(ImVec2(curr_grab_pos, bb.Min.y), ImVec2(curr_grab_pos, bb.Max.y)); + } + else + { + new_grab_bb = ImRect(ImVec2(bb.Min.x, new_grab_pos), ImVec2(bb.Max.x, new_grab_pos)); + curr_grab_bb = ImRect(ImVec2(bb.Min.x, curr_grab_pos), ImVec2(bb.Max.x, curr_grab_pos)); + } + + // Draw all the things + if (isDown && hovered) + window->DrawList->AddRectFilled(ImVec2(0, 0), ImGui::GetIO().DisplaySize, ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.5f))); + + // Whiter, more opaque line up to mouse position + if (hovered) + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(new_grab_bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)), 4); + + if (isDown && hovered) { + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(new_grab_bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.00f)), 4); + window->DrawList->AddCircleFilled(ImVec2(new_grab_bb.Min.x, new_grab_bb.Min.y + ((new_grab_bb.Max.y - new_grab_bb.Min.y) / 2)), 8, ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f))); + window->DrawList->AddText(ImVec2(new_grab_bb.GetCenter().x - valuesize.x / 2, bb.Min.y), ImColor(255, 255, 255), value, label); + } + + // Progress bar + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(curr_grab_bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f)), 4); + + // Grey background line + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImVec2(bb.Max.x, bb.Min.y + ((bb.Max.y - bb.Min.y) / 2)), ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 0.5f)), 4); + + //window->DrawList->AddRectFilled(ImVec2(grab_bb.Min.x, bb.Min.y + 2), ImVec2(grab_bb.Max.x + valuesize.x, bb.Min.y + 14), ColorConvertFloat4ToU32(ImVec4(0.21f, 0.20f, 0.21f, 1.00f)), 3); + + return value_changed; +} + +bool SliderCustom(const char* label, ImVec4 color, int* v, int v_min, int v_max, float power, const char* format) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = ImGui::CalcItemWidth(); + + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true) * 2.7f; + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 0.5f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + if (!ImGui::ItemAdd(total_bb, id)) + { + ImGui::ItemSize(total_bb, style.FramePadding.y); + return false; + } + + const bool hovered = ImGui::ItemHoverable(frame_bb, id); + if (hovered) + ImGui::SetHoveredID(id); + + if (!format) + format = "%d"; + + bool start_text_input = false; + const bool tab_focus_requested = ImGui::FocusableItemRegister(window, g.ActiveId == id); + if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) + { + ImGui::SetActiveID(id, window); + ImGui::FocusWindow(window); + + if (tab_focus_requested || g.IO.KeyCtrl) + { + start_text_input = true; + g.ScalarAsInputTextId = 0; + } + } + if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + return ImGui::InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_S32, v, format); + + ImGui::ItemSize(total_bb, style.FramePadding.y); + + char value_buf[64]; + const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); + const bool value_changed = SliderCustomBehavior(frame_bb, id, v, v_min, v_max, power, ImGuiSliderFlags_None, color, ImGui::CalcTextSize(value_buf, NULL, true), value_buf_end, value_buf); + + if (label_size.x > 0.0f) + ImGui::RenderText(ImVec2(frame_bb.Min.x + style.ItemInnerSpacing.x, frame_bb.Min.y + 25), label); + + return value_changed; +} } // namespace OSD