Исходник ImGui Slider(animated) with custom value render

ставь чайник, зажигай плиту
Эксперт
Статус
Оффлайн
Регистрация
22 Май 2020
Сообщения
1,444
Реакции[?]
1,092
Поинты[?]
10K
ImGui: v1.79



Под 'custom value render' я подразумеваю непосредственно рендер значения слайдера при наведении/использовании этого самого слайдера. В чём проблема обычного RenderFrame? Последующие элементы перекроют ваш фрейм.

Source code:
C++:
static std::map<ImGuiID, float> padding_anim;

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);

    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
    const ImRect total_bb(frame_bb.Min - ImVec2(0, label_size.y + style.ItemInnerSpacing.y), frame_bb.Max);

    ItemSize(total_bb, style.FramePadding.y);
    if (!ItemAdd(total_bb, id, &frame_bb))
        return false;

    // Tabbing or CTRL-clicking on Slider turns it into an input box
    const bool hovered = ItemHoverable(frame_bb, id);
    const bool hovered_plus = ItemHoverable(total_bb, id);

    const bool temp_input_allowed = false;
    bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
    if (!temp_input_is_active)
    {
        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)
        {
            SetActiveID(id, window);
            SetFocusID(id, window);
            FocusWindow(window);
            g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
            if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id))
            {
                temp_input_is_active = true;
                FocusableItemUnregister(window);
            }
        }
    }

    if (temp_input_is_active)
    {
        // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set
        const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 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(ImGuiCol_FrameBg);
    RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);
    
    // Slider behavior
    ImRect 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);

    if (grab_bb.Max.x > grab_bb.Min.x)
        RenderFrame(frame_bb.Min, ImVec2(grab_bb.Max.x, frame_bb.Max.y), GetColorU32(g_menu.menu_color.Value), true, g.Style.FrameRounding);

    // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
    char value_buf[64];
    const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
    
    // label
    if (label_size.x > 0)
        RenderText(ImVec2(frame_bb.Min.x, frame_bb.Min.y - style.ItemInnerSpacing.y - label_size.y), label);

    // value size
    const ImVec2 value_size = CalcTextSize(value_buf, value_buf_end, true);
    
    auto it_padding = padding_anim.find(id);
    if (it_padding == padding_anim.end())
    {
        padding_anim.insert({ id, {0.f} });
        it_padding = padding_anim.find(id);
    }

    it_padding->second = ImClamp(it_padding->second + (2.5f * GetIO().DeltaTime * (hovered_plus || GetActiveID() == id ? 1.f : -1.f)), 0.f, 1.f);

    // value
    if (value_size.x > 0.0f && it_padding->second > 0.f)
    {
        auto value_col = GetColorU32(ImGuiCol_FrameBg, it_padding->second);
        PushStyleVar(ImGuiStyleVar_Alpha, it_padding->second);

        char window_name[16];
        ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##tp_%s", label);

        SetNextWindowPos(frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 - ImVec2(value_size.x / 2 + 3.f, 0.f));
        SetNextWindowSize((frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 + ImVec2(value_size.x / 2 + 3.f, value_size.y + 6)) - (frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 - ImVec2(value_size.x / 2 + 3.f, 0.f)));
        SetNextWindowBgAlpha(it_padding->second);

        ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
            ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration;

        Begin(window_name, NULL, flags);

        RenderFrame(frame_bb.Min + ImVec2(0.f, (frame_bb.Max.y - frame_bb.Min.y)), frame_bb.Min + ImVec2((frame_bb.Max.x - frame_bb.Min.x), (frame_bb.Max.y - frame_bb.Min.y) + value_size.y + 6), GetColorU32(ImGuiCol_FrameBg), GetStyle().WindowRounding);
        RenderTextClipped(frame_bb.Min + ImVec2(0.f, (frame_bb.Max.y - frame_bb.Min.y)), frame_bb.Min + ImVec2((frame_bb.Max.x - frame_bb.Min.x), (frame_bb.Max.y - frame_bb.Min.y) + value_size.y + 6), value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
        
        End();

        PopStyleVar();
    }

    return value_changed;
 
Забаненный
Статус
Оффлайн
Регистрация
22 Апр 2020
Сообщения
731
Реакции[?]
752
Поинты[?]
1K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Эт конечно прикольно,
но что это, з0чем
1614857477289.png
 
ставь чайник, зажигай плиту
Эксперт
Статус
Оффлайн
Регистрация
22 Май 2020
Сообщения
1,444
Реакции[?]
1,092
Поинты[?]
10K
Эт конечно прикольно,
но что это, з0чем
Посмотреть вложение 135347
В чём проблема обычного RenderFrame? Последующие элементы перекроют ваш фрейм.
Так как в ImGui идёт последовательный рендер, то без вызова нового окна, RenderFrame будет перекрыт последующими элементами, поэтому приходится использовать вызов нового окна (Как раз на этом базируется тултип в ImGui)
 
oh, where's your fuckin god?
Забаненный
Статус
Оффлайн
Регистрация
22 Июн 2020
Сообщения
265
Реакции[?]
43
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
ImGui: v1.79



Под 'custom value render' я подразумеваю непосредственно рендер значения слайдера при наведении/использовании этого самого слайдера. В чём проблема обычного RenderFrame? Последующие элементы перекроют ваш фрейм.

Source code:
C++:
static std::map<ImGuiID, float> padding_anim;

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);

    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
    const ImRect total_bb(frame_bb.Min - ImVec2(0, label_size.y + style.ItemInnerSpacing.y), frame_bb.Max);

    ItemSize(total_bb, style.FramePadding.y);
    if (!ItemAdd(total_bb, id, &frame_bb))
        return false;

    // Tabbing or CTRL-clicking on Slider turns it into an input box
    const bool hovered = ItemHoverable(frame_bb, id);
    const bool hovered_plus = ItemHoverable(total_bb, id);

    const bool temp_input_allowed = false;
    bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
    if (!temp_input_is_active)
    {
        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)
        {
            SetActiveID(id, window);
            SetFocusID(id, window);
            FocusWindow(window);
            g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
            if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id))
            {
                temp_input_is_active = true;
                FocusableItemUnregister(window);
            }
        }
    }

    if (temp_input_is_active)
    {
        // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set
        const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 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(ImGuiCol_FrameBg);
    RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);
   
    // Slider behavior
    ImRect 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);

    if (grab_bb.Max.x > grab_bb.Min.x)
        RenderFrame(frame_bb.Min, ImVec2(grab_bb.Max.x, frame_bb.Max.y), GetColorU32(g_menu.menu_color.Value), true, g.Style.FrameRounding);

    // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
    char value_buf[64];
    const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
   
    // label
    if (label_size.x > 0)
        RenderText(ImVec2(frame_bb.Min.x, frame_bb.Min.y - style.ItemInnerSpacing.y - label_size.y), label);

    // value size
    const ImVec2 value_size = CalcTextSize(value_buf, value_buf_end, true);
   
    auto it_padding = padding_anim.find(id);
    if (it_padding == padding_anim.end())
    {
        padding_anim.insert({ id, {0.f} });
        it_padding = padding_anim.find(id);
    }

    it_padding->second = ImClamp(it_padding->second + (2.5f * GetIO().DeltaTime * (hovered_plus || GetActiveID() == id ? 1.f : -1.f)), 0.f, 1.f);

    // value
    if (value_size.x > 0.0f && it_padding->second > 0.f)
    {
        auto value_col = GetColorU32(ImGuiCol_FrameBg, it_padding->second);
        PushStyleVar(ImGuiStyleVar_Alpha, it_padding->second);

        char window_name[16];
        ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##tp_%s", label);

        SetNextWindowPos(frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 - ImVec2(value_size.x / 2 + 3.f, 0.f));
        SetNextWindowSize((frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 + ImVec2(value_size.x / 2 + 3.f, value_size.y + 6)) - (frame_bb.Max - ImVec2(frame_bb.Max.x - frame_bb.Min.x, 0) / 2 - ImVec2(value_size.x / 2 + 3.f, 0.f)));
        SetNextWindowBgAlpha(it_padding->second);

        ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
            ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration;

        Begin(window_name, NULL, flags);

        RenderFrame(frame_bb.Min + ImVec2(0.f, (frame_bb.Max.y - frame_bb.Min.y)), frame_bb.Min + ImVec2((frame_bb.Max.x - frame_bb.Min.x), (frame_bb.Max.y - frame_bb.Min.y) + value_size.y + 6), GetColorU32(ImGuiCol_FrameBg), GetStyle().WindowRounding);
        RenderTextClipped(frame_bb.Min + ImVec2(0.f, (frame_bb.Max.y - frame_bb.Min.y)), frame_bb.Min + ImVec2((frame_bb.Max.x - frame_bb.Min.x), (frame_bb.Max.y - frame_bb.Min.y) + value_size.y + 6), value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
       
        End();

        PopStyleVar();
    }

    return value_changed;
Классно получилось,но почему там niggers?
 
эс-те́т
Забаненный
Статус
Оффлайн
Регистрация
8 Дек 2019
Сообщения
178
Реакции[?]
270
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Так как в ImGui идёт последовательный рендер, то без вызова нового окна, RenderFrame будет перекрыт последующими элементами, поэтому приходится использовать вызов нового окна (Как раз на этом базируется тултип в ImGui)
Есть такая штука, ImGui::GetOverlayDrawList(), она как раз для этого придумана
 
Забаненный
Статус
Оффлайн
Регистрация
22 Апр 2020
Сообщения
731
Реакции[?]
752
Поинты[?]
1K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
ставь чайник, зажигай плиту
Эксперт
Статус
Оффлайн
Регистрация
22 Май 2020
Сообщения
1,444
Реакции[?]
1,092
Поинты[?]
10K
Сверху Снизу