stim::debug_ui_interface struct

Interface for enabling an immediate-mode GUI for debugging purposes.

Image
An example debug_ui_interface.

Example

An implementation using Dear ImGui:

#include <imgui/imgui.h>
#include <stim/stim.h>

class imgui_interface final : public stim::debug_ui_interface
{
  private:
    struct canvas_data
    {
        ImVec2 min;
        ImVec2 max;
        uint32_t colour;
        ImDrawList* draw_list = {};
    } canvas;

  public:
    bool window_begin(stim::string_view title,
                      stim::debug_ui_groups /*groups*/) noexcept override
    {
        return ImGui::Begin(title.data());
    }

    void window_end(bool /* was_visible */) noexcept override
    {
        ImGui::End();
    }

    bool section_begin(stim::string_view title) noexcept override
    {
        return ImGui::CollapsingHeader(title.data(), ImGuiTreeNodeFlags_DefaultOpen);
    }

    void section_end(bool /* was_visible */) noexcept override
    {
        // no-op
    }

    bool subsection_begin(stim::string_view title) noexcept override
    {
        return ImGui::TreeNodeEx(title.data(), ImGuiTreeNodeFlags_DefaultOpen);
    }

    void subsection_end(bool was_visible) noexcept override
    {
        if (was_visible)
            ImGui::TreePop();
    }

    bool indent_begin() noexcept override
    {
        ImGui::Indent();
        return true;
    }

    void indent_end(bool /* was_indented */) noexcept override
    {
        ImGui::Unindent();
    }

    bool colour_begin(uint32_t abgr) noexcept override
    {
        ImGui::PushStyleColor(ImGuiCol_Text, abgr);
        return true;
    }

    void colour_end(bool /*was_coloured*/) noexcept override
    {
        ImGui::PopStyleColor();
    }

    stim::vec2 measure_text(stim::string_view str, float wrap_width) const noexcept override
    {
        const auto size =
            ImGui::CalcTextSize(str.data(), str.data() + str.length(), false, wrap_width);
        return { size.x, size.y };
    }

    void text(stim::string_view str) noexcept override
    {
        ImGui::TextUnformatted(str.data(), str.data() + str.length());
    }

    void value(stim::string_view name, stim::string_view val) noexcept override
    {
        ImGui::Text("%.*s: %.*s",
                    static_cast<int>(name.length()),
                    name.data(),
                    static_cast<int>(val.length()),
                    val.data());
    }

    bool button(stim::string_view str) noexcept override
    {
        return ImGui::Button(str.data());
    }

    float slider(stim::string_view label, float val, float min, float max) noexcept override
    {
        ImGui::Slider(label.data(), val, min, max);
        return val;
    }

    float content_width() const noexcept override
    {
        return ImGui::GetWindowContentRegionWidth();
    }

    bool canvas_begin(stim::string_view id, const stim::vec2& size) noexcept override
    {
        ImGui::InvisibleButton(id.data(), ImVec2{ size[0], size[1] });
        if (!ImGui::IsItemVisible())
            return false;

        canvas.min       = ImGui::GetItemRectMin();
        canvas.max       = ImGui::GetItemRectMax();
        canvas.colour    = 0xFF000000;
        canvas.draw_list = ImGui::GetWindowDrawList();

        const ImVec2 win_pos      = ImGui::GetWindowPos();
        const ImVec2 win_clip_min = ImGui::GetWindowContentRegionMin();
        const ImVec2 win_clip_max = ImGui::GetWindowContentRegionMax();
        canvas.draw_list->PushClipRect({ std::max(canvas.min.x, win_pos.x + win_clip_min.x),
                                         std::max(canvas.min.y, win_pos.y + win_clip_min.y) },
                                       { std::min(canvas.max.x, win_pos.x + win_clip_max.x),
                                         std::min(canvas.max.y, win_pos.y + win_clip_max.y) },
                                       true);
        return true;
    }

    void canvas_set_colour(uint32_t abgr) noexcept override
    {
        canvas.colour = abgr;
    }

    void canvas_draw_line(const stim::vec2& p1,
                          const stim::vec2& p2,
                          float stroke) noexcept override
    {
        canvas.draw_list->AddLine({ canvas.min.x + p1[0], canvas.min.y + p1[1] },
                                  { canvas.min.x + p2[0], canvas.min.y + p2[1] },
                                  canvas.colour,
                                  stroke);
    }

    void canvas_draw_rect(const stim::vec2& pos,
                          const stim::vec2& size,
                          float weight) noexcept override
    {
        const ImVec2 min = ImVec2{ canvas.min.x + pos[0], canvas.min.y + pos[1] };
        canvas.draw_list->AddRect(min,
                                  ImVec2{ min.x + size[0], min.y + size[1] },
                                  canvas.colour,
                                  0.0f,
                                  ImDrawCornerFlags_All,
                                  weight);
    }

    void canvas_fill_rect(const stim::vec2& pos, const stim::vec2& size) noexcept override
    {
        const ImVec2 min = ImVec2{ canvas.min.x + pos[0], canvas.min.y + pos[1] };
        canvas.draw_list->AddRectFilled(min,
                                        ImVec2{ min.x + size[0], min.y + size[1] },
                                        canvas.colour);
    }

    void canvas_draw_text(stim::string_view str,
                          const stim::vec2& pos,
                          float wrap_width) noexcept override
    {
        canvas.draw_list->AddText(ImGui::GetFont(),
                                  ImGui::GetFontSize(),
                                  ImVec2{ canvas.min.x + pos[0], canvas.min.y + pos[1] },
                                  canvas.colour,
                                  str.data(),
                                  str.data() + str.length(),
                                  wrap_width);
    }

    void canvas_end(bool was_visible) noexcept override
    {
        if (was_visible)
        {
            canvas.draw_list->PopClipRect();
            canvas.draw_list = nullptr;
        }
    }
};

Public functions

auto content_width() const -> float pure virtual noexcept
Returns the width of the window minus any internal margins, padding and indentation.

Canvases

Image
A canvas being used to draw the memory usage visualization.
auto canvas_begin(string_view id, const vec2& size) -> bool pure virtual noexcept
Requests the beginning of a drawable canvas area.
void canvas_draw_line(const vec2& from, const vec2& to, float width) pure virtual noexcept
Draws a single line segment.
void canvas_draw_rect(const vec2& pos, const vec2& size, float width) pure virtual noexcept
Draws the outline of a rectangle.
void canvas_draw_text(string_view str, const vec2& pos, float wrap_width = -1.0f) pure virtual noexcept
Draws some text.
void canvas_end(bool was_visible) pure virtual noexcept
Signals the end of a canvas.
void canvas_fill_rect(const vec2& pos, const vec2& size) pure virtual noexcept
Fills a rectangle.
void canvas_set_colour(uint32_t abgr) pure virtual noexcept
Sets the current canvas draw colour.

Text

auto button(string_view label) -> bool pure virtual noexcept
Renders a text button.
auto colour_begin(uint32_t abgr) -> bool pure virtual noexcept
Requests that the primary text colour be changed until the next call to colour_end().
void colour_end(bool was_coloured) pure virtual noexcept
Signals the end of a custom text colour.
auto measure_text(string_view str, float wrap_width) const -> vec2 pure virtual noexcept
Calculates the dimensions of some text if it were drawn at an arbitrary location.
auto slider(string_view label, float val, float min, float max) -> float pure virtual noexcept
Renders a slider (or similar widget) for adjusting a range-bound numeric value.
void text(string_view str) pure virtual noexcept
Emits some text.
void value(string_view name, string_view val) pure virtual noexcept
Emits a named value (i.e. a key-value pair).

Windows and sections

auto indent_begin() -> bool pure virtual noexcept
Requests the beginning of an indented region of content.
void indent_end(bool was_indented) pure virtual noexcept
Signals the end of an indented region of content.
auto section_begin(string_view title) -> bool pure virtual noexcept
Requests the beginning of a top-level window section.
void section_end(bool was_visible) pure virtual noexcept
Signals the end of a top-level window section's content.
auto subsection_begin(string_view title) -> bool pure virtual noexcept
Requests the beginning of a window subsection.
void subsection_end(bool was_visible) pure virtual noexcept
Signals the end of a window subsection's content.
auto window_begin(string_view title, debug_ui_groups groups) -> bool pure virtual noexcept
Requests the beginning of a window.
void window_end(bool was_visible) pure virtual noexcept
Signals the end of a window's content.

Function documentation

bool stim::debug_ui_interface::canvas_begin(string_view id, const vec2& size) pure virtual noexcept

Requests the beginning of a drawable canvas area.

Parameters
id A unique identifier for the canvas.
size The size of the canvas.
Returns True if the canvas will be visible, false otherwise (occluded, clipped, not supported, etc.).

void stim::debug_ui_interface::canvas_draw_line(const vec2& from, const vec2& to, float width) pure virtual noexcept

Draws a single line segment.

Parameters
from The line's start position.
to The line's end position.
width The line's stroke width.

void stim::debug_ui_interface::canvas_draw_rect(const vec2& pos, const vec2& size, float width) pure virtual noexcept

Draws the outline of a rectangle.

Parameters
pos The rectangle's top-left position.
size The rectangle's size.
width The rectangle's stroke width.

void stim::debug_ui_interface::canvas_draw_text(string_view str, const vec2& pos, float wrap_width = -1.0f) pure virtual noexcept

Draws some text.

Parameters
str The text to draw.
pos The position to the text at.
wrap_width The width of the region the text should be wrapped within.

void stim::debug_ui_interface::canvas_end(bool was_visible) pure virtual noexcept

Signals the end of a canvas.

Parameters
was_visible The return value of the corresponding call to canvas_begin().

void stim::debug_ui_interface::canvas_fill_rect(const vec2& pos, const vec2& size) pure virtual noexcept

Fills a rectangle.

Parameters
pos The rectangle's top-left position.
size The rectangle's size.

void stim::debug_ui_interface::canvas_set_colour(uint32_t abgr) pure virtual noexcept

Sets the current canvas draw colour.

Parameters
abgr The colour to set.

bool stim::debug_ui_interface::button(string_view label) pure virtual noexcept

Renders a text button.

Parameters
label The button's label text.
Returns True if the user clicked the button.

bool stim::debug_ui_interface::colour_begin(uint32_t abgr) pure virtual noexcept

Requests that the primary text colour be changed until the next call to colour_end().

Returns True if the new colour could be added to the stack, false otherwise.

void stim::debug_ui_interface::colour_end(bool was_coloured) pure virtual noexcept

Signals the end of a custom text colour.

Parameters
was_coloured The return value of the corresponding call to colour_begin().

vec2 stim::debug_ui_interface::measure_text(string_view str, float wrap_width) const pure virtual noexcept

Calculates the dimensions of some text if it were drawn at an arbitrary location.

Parameters
str The string to measure.
wrap_width The width of the region the text should be wrapped within.
Returns The size of the emitted text's bounding rectangle.

float stim::debug_ui_interface::slider(string_view label, float val, float min, float max) pure virtual noexcept

Renders a slider (or similar widget) for adjusting a range-bound numeric value.

Parameters
label The button's label text.
val The current value of the property being being modified by the slider.
min The minimum acceptable value (inclusive).
max The maximum acceptable value (inclusive).
Returns The new value for the property being manipulated by the slider.

void stim::debug_ui_interface::text(string_view str) pure virtual noexcept

Emits some text.

Parameters
str The string to write.

void stim::debug_ui_interface::value(string_view name, string_view val) pure virtual noexcept

Emits a named value (i.e. a key-value pair).

Parameters
name The name (key) of the value.
val The value to write.

bool stim::debug_ui_interface::indent_begin() pure virtual noexcept

Requests the beginning of an indented region of content.

Returns True if the indent level could be increased, false otherwise.

void stim::debug_ui_interface::indent_end(bool was_indented) pure virtual noexcept

Signals the end of an indented region of content.

Parameters
was_indented The return value of the corresponding call to indent_begin().

bool stim::debug_ui_interface::section_begin(string_view title) pure virtual noexcept

Requests the beginning of a top-level window section.

Parameters
title The section's title.
Returns True if the contents of the section will be visible, false otherwise (occluded, clipped, etc.).
Image
Three window sections.

void stim::debug_ui_interface::section_end(bool was_visible) pure virtual noexcept

Signals the end of a top-level window section's content.

Parameters
was_visible The return value of the corresponding call to section_begin().

bool stim::debug_ui_interface::subsection_begin(string_view title) pure virtual noexcept

Requests the beginning of a window subsection.

Parameters
title The subsection's title.
Returns True if the contents of the subsection will be visible, false otherwise (occluded, clipped, etc.).
Image
A window subsection.

void stim::debug_ui_interface::subsection_end(bool was_visible) pure virtual noexcept

Signals the end of a window subsection's content.

Parameters
was_visible The return value of the corresponding call to subsection_begin().

bool stim::debug_ui_interface::window_begin(string_view title, debug_ui_groups groups) pure virtual noexcept

Requests the beginning of a window.

Parameters
title The window's title.
groups The debug UI groups that will be contained by the window.
Returns True if the contents of the window will be visible, false otherwise (occluded, clipped, etc.).

void stim::debug_ui_interface::window_end(bool was_visible) pure virtual noexcept

Signals the end of a window's content.

Parameters
was_visible The return value of the corresponding call to window_begin().