code:
#pragma once

#include <string>

struct IUndoCommand {
  virtual ~IUndoCommand() = default;
  virtual int type() const = 0;
  virtual bool undo() = 0;
  virtual std::string description() = 0;
  void setIsRedo(const bool isRedoOp) { m_isRedo = isRedoOp; }

protected:
  bool m_isRedo = false;
};

repo_name: Antidote/openrpgeditor

license: mit


code:
/**
 * @file ImGuiNotify.hpp
 * @brief A header-only library for creating toast notifications with ImGui.
 *
 * Based on imgui-notify by patrickcjk
 * https://github.com/patrickcjk/imgui-notify
 *
 * @version 0.0.3 WIP by TyomaVader
 * @date 18.01.2024
 */

#ifndef IMGUI_NOTIFY
#define IMGUI_NOTIFY

#pragma once

#include <chrono>     // For the notifications timed dissmiss
#include <functional> // For storing the code, which executest on the button click in the notification
#include <string>
#include <vector> // Vector for storing notifications list

#include "imgui.h"
#include "imgui_internal.h"

#include "IconsFontAwesome6.h"

/**
 * CONFIGURATION SECTION Start
 */

#define NOTIFY_MAX_MSG_LENGTH 4096     // Max message content length
#define NOTIFY_PADDING_X 20.f          // Bottom-left X padding
#define NOTIFY_PADDING_Y 20.f          // Bottom-left Y padding
#define NOTIFY_PADDING_MESSAGE_Y 10.f  // Padding Y between each message
#define NOTIFY_FADE_IN_OUT_TIME 150    // Fade in and out duration
#define NOTIFY_DEFAULT_DISMISS 3000    // Auto dismiss after X ms (default, applied only of no data provided in constructors)
#define NOTIFY_OPACITY 0.8f            // 0-1 Toast opacity
#define NOTIFY_USE_SEPARATOR false     // If true, a separator will be rendered between the title and the content
#define NOTIFY_USE_DISMISS_BUTTON true // If true, a dismiss button will be rendered in the top right corner of the toast
#define NOTIFY_RENDER_LIMIT 5          // Max number of toasts rendered at the same time. Set to 0 for unlimited

/**
 * CONFIGURATION SECTION End
 */

static const ImGuiWindowFlags NOTIFY_DEFAULT_TOAST_FLAGS =
    ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing;

#define NOTIFY_NULL_OR_EMPTY(str) (!str || !strlen(str))
#define NOTIFY_FORMAT(fn, format, ...)                                                                                \
  if (format) {                                                                                \
    va_list args;                                                                                \
    va_start(args, format);                                                                                \
    fn(format, args, ##__VA_ARGS__);                                                                                \
    va_end(args);                                                                                \
  }

enum class ImGuiToastType : uint8_t { None, Success, Warning, Error, Info, COUNT };

enum class ImGuiToastPhase : uint8_t { FadeIn, Wait, FadeOut, Expired, COUNT };

enum class ImGuiToastPos : uint8_t { TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight, Center, COUNT };

/**
 * @brief A class for creating toast notifications with ImGui.
 */
class ImGuiToast {
private:
  ImGuiWindowFlags flags = NOTIFY_DEFAULT_TOAST_FLAGS;

  ImGuiToastType type = ImGuiToastType::None;
  char title[NOTIFY_MAX_MSG_LENGTH];
  char content[NOTIFY_MAX_MSG_LENGTH];

  int dismissTime = NOTIFY_DEFAULT_DISMISS;
  std::chrono::system_clock::time_point creationTime = std::chrono::system_clock::now();

  std::function<void()> onButtonPress = nullptr; // A lambda variable, which will be executed when button in notification is pressed
  char buttonLabel[NOTIFY_MAX_MSG_LENGTH];

private:
  // Setters

  inline void setTitle(const char* format, va_list args) { vsnprintf(this->title, sizeof(this->title), format, args); }

  inline void setContent(const char* format, va_list args) { vsnprintf(this->content, sizeof(this->content), format, args); }

  inline void setButtonLabel(const char* format, va_list args) { vsnprintf(this->buttonLabel, sizeof(this->buttonLabel), format, args); }

public:
  /**
   * @brief Set the title of the toast notification.
   *
   * @param format The format string for the title.
   * @param ... The arguments for the format string.
   */
  inline void setTitle(const char* format, ...) { NOTIFY_FORMAT(this->setTitle, format); }

  /**
   * @brief Set the content of the toast notification.
   *
   * @param format The format string for the content.
   * @param ... The arguments for the format string.
   */
  inline void setContent(const char* format, ...) { NOTIFY_FORMAT(this->setContent, format); }

  /**
   * @brief Set the type of the toast notification.
   *
   * @param type The type of the toast notification.
   */
  inline void setType(const ImGuiToastType& type) {
    IM_ASSERT(type < ImGuiToastType::COUNT);
    this->type = type;
  };

  /**
   * @brief Set the ImGui window flags for the notification.
   *
   * @param flags ImGui window flags to set.
   */
  inline void setWindowFlags(const ImGuiWindowFlags& flags) { this->flags = flags; }

  /**
   * @brief Set the function to run on the button click in the notification.
   *
   * @param onButtonPress std::fuction or lambda expression, which contains the code for execution.
   */
  inline void setOnButtonPress(const std::function<void()>& onButtonPress) { this->onButtonPress = onButtonPress; }

  /**
   * @brief Set the label for the button in the notification.
   *
   * @param format The format string for the label.
   * @param ... The arguments for the format string.
   */
  inline void setButtonLabel(const char* format, ...) { NOTIFY_FORMAT(this->setButtonLabel, format); }

public:
  // Getters

  /**
   * @brief Get the title of the toast notification.
   *
   * @return const char* The title of the toast notification.
   */
  inline const char* getTitle() { return this->title; };

  /**
   * @brief Get the default title of the toast notification based on its type.
   *
   * @return const char* The default title of the toast notification.
   */
  inline const char* getDefaultTitle() {
    if (!strlen(this->title)) {
      switch (this->type) {
      case ImGuiToastType::None:
        return nullptr;
      case ImGuiToastType::Success:
        return "Success";
      case ImGuiToastType::Warning:
        return "Warning";
      case ImGuiToastType::Error:
        return "Error";
      case ImGuiToastType::Info:
        return "Info";
      default:
        return nullptr;
      }
    }

    return this->title;
  };

  /**
   * @brief Get the type of the toast notification.
   *
   * @return ImGuiToastType The type of the toast notification.
   */
  inline ImGuiToastType getType() { return this->type; };

  /**
   * @brief Get the color of the toast notification based on its type.
   *
   * @return ImVec4 The color of the toast notification.
   */
  inline ImVec4 getColor() {
    switch (this->type) {
    case ImGuiToastType::None:
      return {255, 255, 255, 255}; // White
    case ImGuiToastType::Success:
      return {0, 255, 0, 255}; // Green
    case ImGuiToastType::Warning:
      return {255, 255, 0, 255}; // Yellow
    case ImGuiToastType::Error:
      return {255, 0, 0, 255}; // Error
    case ImGuiToastType::Info:
      return {0, 157, 255, 255}; // Blue
    default:
      return {255, 255, 255, 255}; // White
    }
  }

  /**
   * @brief Get the icon of the toast notification based on its type.
   *
   * @return const char* The icon of the toast notification.
   */
  inline const char* getIcon() {
    switch (this->type) {
    case ImGuiToastType::None:
      return nullptr;
    case ImGuiToastType::Success:
      return ICON_FA_CIRCLE_CHECK; // Font Awesome 6
    case ImGuiToastType::Warning:
      return ICON_FA_TRIANGLE_EXCLAMATION; // Font Awesome 6
    case ImGuiToastType::Error:
      return ICON_FA_CIRCLE_EXCLAMATION; // Font Awesome 6
    case ImGuiToastType::Info:
      return ICON_FA_CIRCLE_INFO; // Font Awesome 6
    default:
      return nullptr;
    }
  }

  /**
   * @brief Get the content of the toast notification.
   *
   * @return char* The content of the toast notification.
   */
  inline char* getContent() { return this->content; };

  /**
   * @brief Get the elapsed time in milliseconds since the creation of the object.
   *
   * @return int64_t The elapsed time in milliseconds.
   * @throws An exception with the message "Unsupported platform" if the platform is not supported.
   */
  inline std::chrono::nanoseconds getElapsedTime() { return std::chrono::system_clock::now() - this->creationTime; }

  /**
   * @brief Get the current phase of the toast notification based on the elapsed time since its creation.
   *
   * @return ImGuiToastPhase The current phase of the toast notification.
   *         - ImGuiToastPhase::FadeIn: The notification is fading in.
   *         - ImGuiToastPhase::Wait: The notification is waiting to be dismissed.
   *         - ImGuiToastPhase::FadeOut: The notification is fading out.
   *         - ImGuiToastPhase::Expired: The notification has expired and should be removed.
   */
  inline ImGuiToastPhase getPhase() {
    const int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(getElapsedTime()).count();

    if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismissTime + NOTIFY_FADE_IN_OUT_TIME) {
      return ImGuiToastPhase::Expired;
    } else if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismissTime) {
      return ImGuiToastPhase::FadeOut;
    } else if (elapsed > NOTIFY_FADE_IN_OUT_TIME) {
      return ImGuiToastPhase::Wait;
    } else {
      return ImGuiToastPhase::FadeIn;
    }
  }

  /**
   * Returns the percentage of fade for the notification.
   * @return The percentage of fade for the notification.
   */
  inline float getFadePercent() {
    const ImGuiToastPhase phase = getPhase();
    const int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(getElapsedTime()).count();

    if (phase == ImGuiToastPhase::FadeIn) {
      return ((float)elapsed / (float)NOTIFY_FADE_IN_OUT_TIME) * NOTIFY_OPACITY;
    } else if (phase == ImGuiToastPhase::FadeOut) {
      return (1.f - (((float)elapsed - (float)NOTIFY_FADE_IN_OUT_TIME - (float)this->dismissTime) / (float)NOTIFY_FADE_IN_OUT_TIME)) * NOTIFY_OPACITY;
    }

    return 1.f * NOTIFY_OPACITY;
  }

  /**
   * @return ImGui window flags for the notification.
   */
  inline ImGuiWindowFlags getWindowFlags() { return this->flags; }

  /**
   * @return The function, which is executed on the button click in the notification.
   */
  inline std::function<void()> getOnButtonPress() { return this->onButtonPress; }

  /**
   * @return The label on the button in notification.
   */
  inline const char* getButtonLabel() { return this->buttonLabel; }

public:
  // Constructors

  /**
   * @brief Creates a new ImGuiToast object with the specified type and dismiss time.
   *
   * @param type The type of the toast.
   * @param dismissTime The time in milliseconds after which the toast should be dismissed. Default is NOTIFY_DEFAULT_DISMISS.
   */
  ImGuiToast(ImGuiToastType type, int dismissTime = NOTIFY_DEFAULT_DISMISS) {
    IM_ASSERT(type < ImGuiToastType::COUNT);

    this->type = type;
    this->dismissTime = dismissTime;

    this->creationTime = std::chrono::system_clock::now();

    memset(this->title, 0, sizeof(this->title));
    memset(this->content, 0, sizeof(this->content));
  }

  /**
   * @brief Constructor for creating an ImGuiToast object with a specified type and message format.
   *
   * @param type The type of the toast message.
   * @param format The format string for the message.
   * @param ... The variable arguments to be formatted according to the format string.
   */
  ImGuiToast(ImGuiToastType type, const char* format, ...)
  : ImGuiToast(type) {
    NOTIFY_FORMAT(this->setContent, format);
  }

  /**
   * @brief Constructor for creating a new ImGuiToast object with a specified type, dismiss time, and content format.
   *
   * @param type The type of the toast message.
   * @param dismissTime The time in milliseconds before the toast message is dismissed.
   * @param format The format string for the content of the toast message.
   * @param ... The variable arguments to be formatted according to the format string.
   */
  ImGuiToast(ImGuiToastType type, int dismissTime, const char* format, ...)
  : ImGuiToast(type, dismissTime) {
    NOTIFY_FORMAT(this->setContent, format);
  }

  /**
   * @brief Constructor for creating a new ImGuiToast object with a specified type, dismiss time, title format, content format and a button.
   *
   * @param type The type of the toast message.
   * @param dismissTime The time in milliseconds before the toast message is dismissed.
   * @param buttonLabel The label for the button.
   * @param onButtonPress The lambda function to be executed when the button is pressed.
   * @param format The format string for the content of the toast message.
   * @param ... The variable arguments to be formatted according to the format string.
   */
  ImGuiToast(ImGuiToastType type, int dismissTime, const char* buttonLabel, const std::function<void()>& onButtonPress, const char* format, ...)
  : ImGuiToast(type, dismissTime) {
    NOTIFY_FORMAT(this->setContent, format);

    this->onButtonPress = onButtonPress;
    this->setButtonLabel(buttonLabel);
  }
};

namespace ImGui {
inline std::vector<ImGuiToast> notifications;

/**
 * Inserts a new notification into the notification queue.
 * @param toast The notification to be inserted.
 */
inline void InsertNotification(const ImGuiToast& toast) { notifications.push_back(toast); }

/**
 * @brief Removes a notification from the list of notifications.
 *
 * @param index The index of the notification to remove.
 */
inline void RemoveNotification(int index) { notifications.erase(notifications.begin() + index); }

/**
 * Renders all notifications in the notifications vector.
 * Each notification is rendered as a toast window with a title, content and an optional icon.
 * If a notification is expired, it is removed from the vector.
 */
inline void RenderNotifications() {
  const ImVec2 mainWindowSize = GetMainViewport()->Size;

  float height = 0.f;

  for (size_t i = 0; i < notifications.size(); ++i) {
    ImGuiToast* currentToast = &notifications[i];

    // Remove toast if expired
    if (currentToast->getPhase() == ImGuiToastPhase::Expired) {
      RemoveNotification(i);
      continue;
    }

#if NOTIFY_RENDER_LIMIT > 0
    if (i > NOTIFY_RENDER_LIMIT) {
      continue;
    }
#endif

    // Get icon, title and other data
    const char* icon = currentToast->getIcon();
    const char* title = currentToast->getTitle();
    const char* content = currentToast->getContent();
    const char* defaultTitle = currentToast->getDefaultTitle();
    const float opacity = currentToast->getFadePercent(); // Get opacity based of the current phase

    // Window rendering
    ImVec4 textColor = currentToast->getColor();
    textColor.w = opacity;

    // Generate new unique name for this toast
    char windowName[50];
#ifdef _WIN32
    sprintf_s(windowName, "##TOAST%d", (int)i);
#elif defined(__linux__) || defined(__EMSCRIPTEN__)
    sprintf(windowName, "##TOAST%d", (int)i);
#else
    throw "Unsupported platform";
#endif

    // PushStyleColor(ImGuiCol_Text, textColor);
    SetNextWindowBgAlpha(opacity);

    // Set notification window position to bottom right corner of the main window, considering the main window size and location in relation to the display
    ImVec2 mainWindowPos = GetMainViewport()->Pos;
    SetNextWindowPos(ImVec2(mainWindowPos.x + mainWindowSize.x - NOTIFY_PADDING_X, mainWindowPos.y + mainWindowSize.y - NOTIFY_PADDING_Y - height), ImGuiCond_Always, ImVec2(1.0f, 1.0f));

    // Set notification window flags
    if (!NOTIFY_USE_DISMISS_BUTTON && currentToast->getOnButtonPress() == nullptr) {
      currentToast->setWindowFlags(NOTIFY_DEFAULT_TOAST_FLAGS | ImGuiWindowFlags_NoInputs);
    }

    Begin(windowName, nullptr, currentToast->getWindowFlags());

    // Render over all other windows
    BringWindowToDisplayFront(GetCurrentWindow());

    // Here we render the toast content
    {
      PushTextWrapPos(mainWindowSize.x / 3.f); // We want to support multi-line text, this will wrap the text after 1/3 of the screen width

      bool wasTitleRendered = false;

      // If an icon is set
      if (!NOTIFY_NULL_OR_EMPTY(icon)) {
        // Text(icon); // Render icon text
        TextColored(textColor, "%s", icon);
        wasTitleRendered = true;
      }

      // If a title is set
      if (!NOTIFY_NULL_OR_EMPTY(title)) {
        // If a title and an icon is set, we want to render on same line
        if (!NOTIFY_NULL_OR_EMPTY(icon))
          SameLine();

        Text("%s", title); // Render title text
        wasTitleRendered = true;
      } else if (!NOTIFY_NULL_OR_EMPTY(defaultTitle)) {
        if (!NOTIFY_NULL_OR_EMPTY(icon))
          SameLine();

        Text("%s", defaultTitle); // Render default title text (ImGuiToastType_Success -> "Success", etc...)
        wasTitleRendered = true;
      }

      // If a dismiss button is enabled
      if (NOTIFY_USE_DISMISS_BUTTON) {
        // If a title or content is set, we want to render the button on the same line
        if (wasTitleRendered || !NOTIFY_NULL_OR_EMPTY(content)) {
          SameLine();
        }

        // Render the dismiss button on the top right corner
        // NEEDS TO BE REWORKED
        float scale = 0.8f;

        if (CalcTextSize(content).x > GetWindowContentRegionMax().x) {
          scale = 0.95f;
        }

        SetCursorPosX(GetCursorPosX() + (GetWindowSize().x - GetCursorPosX()) * scale);

        // If the button is pressed, we want to remove the notification
        if (Button(ICON_FA_XMARK)) {
          RemoveNotification(i);
        }
      }

      // In case ANYTHING was rendered in the top, we want to add a small padding so the text (or icon) looks centered vertically
      if (wasTitleRendered && !NOTIFY_NULL_OR_EMPTY(content)) {
        SetCursorPosY(GetCursorPosY() + 5.f); // Must be a better way to do this!!!!
      }

      // If a content is set
      if (!NOTIFY_NULL_OR_EMPTY(content)) {
        if (wasTitleRendered) {
#if NOTIFY_USE_SEPARATOR
          Separator();
#endif
        }

        Text("%s", content); // Render content text
      }

      // If a button is set
      if (currentToast->getOnButtonPress() != nullptr) {
        // If the button is pressed, we want to execute the lambda function
        if (Button(currentToast->getButtonLabel())) {
          currentToast->getOnButtonPress()();
        }
      }

      PopTextWrapPos();
    }

    // Save height for next toasts
    height += GetWindowHeight() + NOTIFY_PADDING_MESSAGE_Y;

    // End
    End();
  }
}
} // namespace ImGui

#endif


code:
#include "Core/ImGuiExt/ImGuiParsedText.hpp"
#include "Core/ImGuiExt/TextParser.hpp"

#include "imgui_internal.h"

#include <memory>

namespace ImGui {

void ImFont_RenderAnsiText(ImFont* font, ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f,
                           bool cpu_fine_clip = false) {
  const int len = strlen(text_begin);
  if (!text_end)
    text_end = text_begin + len; // ImGui functions generally already provides a valid text_end,

  // so this is merely to handle direct calls.

  // Align to be pixel perfect
  pos.x = (float)(int)pos.x;
  pos.y = (float)(int)pos.y;
  float x = pos.x;
  float y = pos.y;
  if (y > clip_rect.w)
    return;

  std::unique_ptr<char[]> char_buf(new char[len + 1]);
  std::unique_ptr<ImU32[]> col_buf(new ImU32[len + 1]);

  const float scale = font->Scale;
  const float line_height = font->LastBaked->Size * scale;
  const bool word_wrap_enabled = (wrap_width > 0.0f);
  const char* word_wrap_eol = NULL;
  // Fast-forward to first visible line
  const char* s = text_begin;
  if (y + line_height < clip_rect.y && !word_wrap_enabled)
    while (y + line_height < clip_rect.y && s < text_end) {
      s = (const char*)memchr(s, '\n', text_end - s);
      s = s ? s + 1 : text_end;
      y += line_height;
    }

  int index = 0;
  {
    int skipChars = 0;
    const char* sLocal = s;
    ImU32 temp_col = col;
    while (sLocal < text_end) {
      if (sLocal < text_end && ParseColor(sLocal, &temp_col, &skipChars)) {
        sLocal += skipChars;
      } else {
        col_buf.get()[index] = temp_col;
        char_buf.get()[index] = *sLocal;
        ++index;
        ++sLocal;
      }
    }
    char_buf.get()[index] = '\0';
  }

  text_begin = char_buf.get();
  text_end = text_begin + index;
  s = text_begin;

  const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, word_wrap_enabled ? CalcWrapWidthForPos(GetCurrentWindow()->DC.CursorPos, GetCurrentWindow()->DC.TextWrapPos) : 0.0f);
  // Account of baseline offset
  ImRect bb(pos, pos + text_size);
  ItemSize(text_size);
  if (!ItemAdd(bb, 0))
    return;

  // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
  // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer
  // without a newline will likely crash atm)
  if (text_end - s > 10000 && !word_wrap_enabled) {
    const char* s_end = s;
    float y_end = y;
    while (y_end < clip_rect.w && s_end < text_end) {
      s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
      s = s ? s + 1 : text_end;
      y_end += line_height;
    }
    text_end = s_end;
  }
  if (s == text_end)
    return;

  // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
  const int vtx_count_max = (int)(text_end - s) * 4;
  const int idx_count_max = (int)(text_end - s) * 6;
  const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
  draw_list->PrimReserve(idx_count_max, vtx_count_max);

  ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
  ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
  unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;

  while (s < text_end) {
    if (word_wrap_enabled) {
      // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and
      // not intrusive for what's essentially an uncommon feature.
      if (!word_wrap_eol) {
        word_wrap_eol = font->CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
        if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to
          // minimize the height discontinuity.
          word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s
                           // >= word_wrap_eol below
      }

      if (s >= word_wrap_eol) {
        x = pos.x;
        y += line_height;
        word_wrap_eol = NULL;

        // Wrapping skips upcoming blanks
        while (s < text_end) {
          const char c = *s;
          if (ImCharIsBlankA(c)) {
            s++;
          } else if (c == '\n') {
            s++;
            break;
          } else {
            break;
          }
        }
        continue;
      }
    }

    // Decode and advance source
    unsigned int c = (unsigned int)*s;
    if (c < 0x80) {
      s += 1;
    } else {
      s += ImTextCharFromUtf8(&c, s, text_end);
      if (c == 0) // Malformed UTF-8?
        break;
    }

    if (c < 32) {
      if (c == '\n') {
        x = pos.x;
        y += line_height;
        if (y > clip_rect.w)
          break; // break out of main loop
        continue;
      }
      if (c == '\r')
        continue;
    }

    float char_width = 0.0f;
    if (const ImFontGlyph* glyph = font->LastBaked->FindGlyph((ImWchar)c)) {
      char_width = glyph->AdvanceX * scale;

      // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
      if (c != ' ' && c != '\t') {
        // We don't do a second finer clipping test on the Y axis as we've already skipped anything before
        // clip_rect.y and exit once we pass clip_rect.w
        float x1 = x + glyph->X0 * scale;
        float x2 = x + glyph->X1 * scale;
        float y1 = y + glyph->Y0 * scale;
        float y2 = y + glyph->Y1 * scale;
        if (x1 <= clip_rect.z && x2 >= clip_rect.x) {
          // Render a character
          float u1 = glyph->U0;
          float v1 = glyph->V0;
          float u2 = glyph->U1;
          float v2 = glyph->V1;

          // CPU side clipping used to fit text in their frame when the frame is too small. Only does
          // clipping for axis aligned quads.
          if (cpu_fine_clip) {
            if (x1 < clip_rect.x) {
              u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
              x1 = clip_rect.x;
            }
            if (y1 < clip_rect.y) {
              v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
              y1 = clip_rect.y;
            }
            if (x2 > clip_rect.z) {
              u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
              x2 = clip_rect.z;
            }
            if (y2 > clip_rect.w) {
              v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
              y2 = clip_rect.w;
            }
            if (y1 >= y2) {
              x += char_width;
              continue;
            }
          }

          // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug
          // builds. Inlined here:
          ImU32 temp_col = col_buf.get()[s - text_begin - 1];
          {
            idx_write[0] = (ImDrawIdx)(vtx_current_idx);
            idx_write[1] = (ImDrawIdx)(vtx_current_idx + 1);
            idx_write[2] = (ImDrawIdx)(vtx_current_idx + 2);
            idx_write[3] = (ImDrawIdx)(vtx_current_idx);
            idx_write[4] = (ImDrawIdx)(vtx_current_idx + 2);
            idx_write[5] = (ImDrawIdx)(vtx_current_idx + 3);
            vtx_write[0].pos.x = x1;
            vtx_write[0].pos.y = y1;
            vtx_write[0].col = temp_col;
            vtx_write[0].uv.x = u1;
            vtx_write[0].uv.y = v1;
            vtx_write[1].pos.x = x2;
            vtx_write[1].pos.y = y1;
            vtx_write[1].col = temp_col;
            vtx_write[1].uv.x = u2;
            vtx_write[1].uv.y = v1;
            vtx_write[2].pos.x = x2;
            vtx_write[2].pos.y = y2;
            vtx_write[2].col = temp_col;
            vtx_write[2].uv.x = u2;
            vtx_write[2].uv.y = v2;
            vtx_write[3].pos.x = x1;
            vtx_write[3].pos.y = y2;
            vtx_write[3].col = temp_col;
            vtx_write[3].uv.x = u1;
            vtx_write[3].uv.y = v2;
            vtx_write += 4;
            vtx_current_idx += 4;
            idx_write += 6;
          }
        }
      }
    }

    x += char_width;
  }

  // Give back unused vertices
  draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
  draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
  draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
  draw_list->_VtxWritePtr = vtx_write;
  draw_list->_IdxWritePtr = idx_write;
  draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
}

void ImDrawList_AddAnsiText(ImDrawList* drawList, ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f,
                            const ImVec4* cpu_fine_clip_rect = NULL) {
  if ((col & IM_COL32_A_MASK) == 0)
    return;

  if (text_end == NULL)
    text_end = text_begin + strlen(text_begin);
  if (text_begin == text_end)
    return;

  // Pull default font/size from the shared ImDrawListSharedData instance
  if (font == NULL)
    font = drawList->_Data->Font;
  if (font_size == 0.0f)
    font_size = drawList->_Data->FontSize;

  // IM_ASSERT(font->ContainerAtlas->TexID == drawList->_TextureStack.back().GetTexID()); // Use high-level ImGui::PushFont()
  //  or low-level
  //  ImDrawList::PushTextureId() to
  //  change font.

  ImVec4 clip_rect = drawList->_ClipRectStack.back();
  if (cpu_fine_clip_rect) {
    clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
    clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
    clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
    clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
  }
  ImFont_RenderAnsiText(font, drawList, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
}

void RenderParsedText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) {
  ImGuiContext& g = *GImGui;
  ImGuiWindow* window = g.CurrentWindow;

  // Hide anything after a '##' string
  const char* text_display_end;
  if (hide_text_after_hash) {
    text_display_end = FindRenderedTextEnd(text, text_end);
  } else {
    if (!text_end)
      text_end = text + strlen(text); // FIXME-OPT
    text_display_end = text_end;
  }

  if (text != text_display_end) {
    ImDrawList_AddAnsiText(window->DrawList, g.Font, g.FontSize, pos, ParseGetCurrentColor(), text, text_display_end);
    if (g.LogEnabled)
      LogRenderedText(&pos, text, text_display_end);
  }
}

void RenderParsedTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) {
  ImGuiContext& g = *GImGui;
  ImGuiWindow* window = g.CurrentWindow;

  if (!text_end)
    text_end = text + strlen(text); // FIXME-OPT

  if (text != text_end) {
    ImDrawList_AddAnsiText(window->DrawList, g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
    if (g.LogEnabled)
      LogRenderedText(&pos, text, text_end);
  }
}

void TextParsedUnformatted(const char* text, const char* text_end) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return;

  ImGuiContext& g = *GImGui;
  IM_ASSERT(text != NULL);
  const char* text_begin = text;
  if (text_end == NULL)
    text_end = text + strlen(text); // FIXME-OPT

  const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
  const float wrap_pos_x = window->DC.TextWrapPos;
  const bool wrap_enabled = wrap_pos_x >= 0.0f;
  const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
  // Render (we don't hide text after ## in this end-user function)
  RenderParsedTextWrapped(text_pos, text_begin, text_end, wrap_width);
}

void TextParsedV(const char* fmt, va_list args) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return;

  ImGuiContext& g = *GImGui;
  const char* text_end = g.TempBuffer.Data + ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.size(), fmt, args);
  TextParsedUnformatted(g.TempBuffer.Data, text_end);
  // assert(ParseGetStackSize() == 1 && "Color stack not exhausted!");
}

void TextParsed(const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  TextParsedV(fmt, args);
  va_end(args);
}

} // namespace ImGui


code:
#pragma once
// Based on and modified from
// https://gist.github.com/ddovod/be210315f285becc6b0e455b775286e1
#include <string>
#include <vector>
// #define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui.h"

namespace ImGui {
void TextParsedV(const char* fmt, va_list args);
void TextParsed(const char* fmt, ...);
} // namespace ImGui


code:
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "imgui.h"
#include "imgui_internal.h"
#include "imgui_stacklayout.h"
#include "OREMath/Size.hpp"

#include <cstdio>
#include <format>

namespace ImGui {
void BeginGroupPanel(const char* name, const ImVec2& size) {
  BeginGroup();

  auto itemSpacing = GetStyle().ItemSpacing;
  PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
  PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));

  auto frameHeight = GetFrameHeight();
  BeginGroup();

  ImVec2 effectiveSize = size;
  if (size.x < 0.0f)
    effectiveSize.x = GetContentRegionAvail().x;
  else
    effectiveSize.x = size.x;
  Dummy(ImVec2(effectiveSize.x, 0.0f));

  Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
  SameLine(0.0f, 0.0f);
  BeginGroup();
  Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
  SameLine(0.0f, 0.0f);
  TextUnformatted(name);
  SameLine(0.0f, 0.0f);
  Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
  BeginGroup();

  PopStyleVar(2);

  GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
  GetCurrentWindow()->Size.x -= frameHeight;

  PushItemWidth(effectiveSize.x - frameHeight);
}

void EndGroupPanel() {
  PopItemWidth();

  auto itemSpacing = GetStyle().ItemSpacing;

  PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
  PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));

  auto frameHeight = GetFrameHeight();

  // workaround for incorrect capture of columns/table width by placing
  // zero-sized dummy element in the same group, this ensure
  // max X cursor position is updated correctly
  SameLine(0.0f, 0.0f);
  Dummy(ImVec2(0.0f, 0.0f));

  EndGroup();

  // GetWindowDrawList()->AddRectFilled(GetItemRectMin(), GetItemRectMax(), IM_COL32(0, 255, 0, 64), 4.0f);

  EndGroup();

  SameLine(0.0f, 0.0f);
  Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
  Dummy(ImVec2(0.0, frameHeight - frameHeight * 0.5f - itemSpacing.y));

  EndGroup();

  auto itemMin = GetItemRectMin();
  auto itemMax = GetItemRectMax();
  // GetWindowDrawList()->AddRectFilled(itemMin, itemMax, IM_COL32(255, 0, 0, 64), 4.0f);

  ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
  GetWindowDrawList()->AddRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f), ImColor(GetStyleColorVec4(ImGuiCol_Border)), halfFrame.x);

  PopStyleVar(2);

  GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
  GetCurrentWindow()->Size.x += frameHeight;

  Dummy(ImVec2(0.0f, 0.0f));

  EndGroup();
}

bool LabelOverLineEdit(const char* id, const char* label, char* string, int len, float width, const char* tooltip, ImGuiInputTextFlags flags) {
  BeginGroup();
  bool ret = false;
  {
    Text("%s", label);
    char* name = (char*)malloc(len);
    strncpy(name, string, len);
    if (width != 0.f) {
      SetNextItemWidth(width);
    }
    if (InputText(id, name, len, flags)) {
      strncpy(string, name, len);
      ret = true;
    }
    if (tooltip != nullptr) {
      SetItemTooltip("%s", tooltip);
    }
    free(name);
  }
  EndGroup();
  return ret;
}
/* Copy of ImGui::Selectable with borders enabled */
bool SelectableWithBorder(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  const ImGuiStyle& style = g.Style;

  // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle.
  ImGuiID id = window->GetID(label);
  ImVec2 label_size = CalcTextSize(label, NULL, true);
  ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
  ImVec2 pos = window->DC.CursorPos;
  pos.y += window->DC.CurrLineTextBaseOffset;
  ItemSize(size, 0.0f);

  // Fill horizontal space
  // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly
  // right-aligned sizes not visibly match other widgets.
  const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0;
  const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x;
  const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
  if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))
    size.x = ImMax(label_size.x, max_x - min_x);

  // Text stays at the submission position, but bounding box may be extended on both sides
  const ImVec2 text_min = pos;
  const ImVec2 text_max(min_x + size.x, pos.y + size.y);

  // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing
  // between selectable.
  // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting
  // CursorPos.
  ImRect bb(min_x, pos.y, text_max.x, text_max.y);
  if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) {
    const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;
    const float spacing_y = style.ItemSpacing.y;
    const float spacing_L = IM_TRUNC(spacing_x * 0.50f);
    const float spacing_U = IM_TRUNC(spacing_y * 0.50f);
    bb.Min.x -= spacing_L;
    bb.Min.y -= spacing_U;
    bb.Max.x += (spacing_x - spacing_L);
    bb.Max.y += (spacing_y - spacing_U);
  }
  // if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); }

  const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
  const ImGuiItemFlags extra_item_flags = disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None;
  bool is_visible;
  if (span_all_columns) {
    // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every
    // Selectable..
    const float backup_clip_rect_min_x = window->ClipRect.Min.x;
    const float backup_clip_rect_max_x = window->ClipRect.Max.x;
    window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
    window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
    is_visible = ItemAdd(bb, id, NULL, extra_item_flags);
    window->ClipRect.Min.x = backup_clip_rect_min_x;
    window->ClipRect.Max.x = backup_clip_rect_max_x;
  } else {
    is_visible = ItemAdd(bb, id, NULL, extra_item_flags);
  }

  const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0;
  if (!is_visible)
    if (!is_multi_select || !g.BoxSelectState.UnclipMode ||
        !g.BoxSelectState.UnclipRect.Overlaps(bb)) // Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd)
      return false;

  const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
  if (disabled_item && !disabled_global) // Only testing this as an optimization
    BeginDisabled();

  // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full
  // push on render only, which would be advantageous since most selectable are not selected.
  if (span_all_columns) {
    if (g.CurrentTable)
      TablePushBackgroundChannel();
    else if (window->DC.CurrentColumns)
      PushColumnsBackground();
    g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasClipRect;
    g.LastItemData.ClipRect = window->ClipRect;
  }

  // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries
  ImGuiButtonFlags button_flags = 0;
  if (flags & ImGuiSelectableFlags_NoHoldingActiveID) {
    button_flags |= ImGuiButtonFlags_NoHoldingActiveId;
  }
  if (flags & ImGuiSelectableFlags_NoSetKeyOwner) {
    button_flags |= ImGuiButtonFlags_NoSetKeyOwner;
  }
  if (flags & ImGuiSelectableFlags_SelectOnClick) {
    button_flags |= ImGuiButtonFlags_PressedOnClick;
  }
  if (flags & ImGuiSelectableFlags_SelectOnRelease) {
    button_flags |= ImGuiButtonFlags_PressedOnRelease;
  }
  if (flags & ImGuiSelectableFlags_AllowDoubleClick) {
    button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
  }
  if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) {
    button_flags |= ImGuiButtonFlags_AllowOverlap;
  }

  // Multi-selection support (header)
  const bool was_selected = selected;
  if (is_multi_select) {
    // Handle multi-select + alter button flags for it
    MultiSelectItemHeader(id, &selected, &button_flags);
  }

  bool hovered, held;
  bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);

  // Multi-selection support (footer)
  if (is_multi_select) {
    MultiSelectItemFooter(id, &selected, &pressed);
  } else {
    // Auto-select when moved into
    // - This will be more fully fleshed in the range-select branch
    // - This is not exposed as it won't nicely work with some user side handling of shift/control
    // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons
    //   - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g.
    //   BeginSelection() calling PushFocusScope())
    //   - (2) usage will fail with clipped items
    //   The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.
    if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId)
      if (g.NavJustMovedToId == id)
        selected = pressed = true;
  }

  // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed
  // with keyboard/gamepad
  if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) {
    if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) {
      SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect)
      if (g.IO.ConfigNavCursorVisibleAuto)
        g.NavCursorVisible = false;
    }
  }
  if (pressed)
    MarkItemEdited(id);

  if (selected != was_selected)
    g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;

  // Render
  if (is_visible) {
    const bool highlighted = hovered || (flags & ImGuiSelectableFlags_Highlight);
    if (highlighted || selected) {
      // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered.
      // Removed that now. (#8106)
      ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
      RenderFrame(bb.Min, bb.Max, col, true, 0.0f);
    }
    if (g.NavId == id) {
      ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding;
      if (is_multi_select)
        nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle
      RenderNavCursor(bb, id, nav_render_cursor_flags);
    }
  }

  if (span_all_columns) {
    if (g.CurrentTable)
      TablePopBackgroundChannel();
    else if (window->DC.CurrentColumns)
      PopColumnsBackground();
  }

  if (is_visible)
    RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);

  // Automatically close popups
  if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
    CloseCurrentPopup();

  if (disabled_item && !disabled_global)
    EndDisabled();

  // Selectable() always returns a pressed state!
  // Users of BeginMultiSelect()/EndMultiSelect() scope: you may call ImGui::IsItemToggledSelection() to retrieve
  // selection toggle, only useful if you need that state updated (e.g. for rendering purpose) before reaching
  // EndMultiSelect().
  IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
  return pressed; //-V1020
}

void ActionTooltip(const char* action, const char* fmt, ...) {
  if (BeginTooltip()) {
    SeparatorText(action);
    va_list args;
    va_start(args, fmt);
    TextV(fmt, args);
    va_end(args);
    EndTooltip();
  }
}

int ButtonGroup(const char* id, const std::vector<std::string>& buttons, const bool isVertical, const std::vector<std::string>& tooltips) {
  int ret = -1;

  if (isVertical) {
    BeginVertical(id);
  } else {
    BeginHorizontal(id);
  }

  const auto& style = GetStyle();
  ImVec2 size;

  // First get the largest button size
  for (const auto& btn : buttons) {
    const auto sz = CalcTextSize(btn.c_str(), nullptr, true);
    if (sz.x > size.x || sz.y > size.y) {
      size = sz;
    }
  }

  // Make sure the button size can fit the text
  size += style.FramePadding * 2.f;

  for (int i = 0; i < buttons.size(); i++) {
    if (ButtonEx(std::format("{}##{}_button_{}", buttons[i], id, i).c_str(), size, ImGuiButtonFlags_AlignTextBaseLine)) {
      ret = i;
    }
    if (i < tooltips.size()) {
      SetItemTooltip("%s", tooltips[i].c_str());
    }
  }
  if (isVertical) {
    EndVertical();
  } else {
    EndHorizontal();
  }

  return ret;
}

ImVec2 GetDPIScaledSize(const ImVec2& size) { return size * GetCurrentContext()->FontScale * GetCurrentWindow()->FontWindowScale; }

float GetDPIScaledValue(const float value) { return value * GetCurrentContext()->FontScale * GetCurrentWindow()->FontWindowScale; }

static bool IsRootOfOpenMenuSet() {
  ImGuiContext& g = *GImGui;
  ImGuiWindow* window = g.CurrentWindow;
  if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu))
    return false;

  // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others
  // (e.g. inside menu bar vs loose menu items) based on parent ID.
  // This would however prevent the use of e.g. PushID() user code submitting menus.
  // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag,
  // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.
  // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup
  // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu.
  // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer.
  // This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still
  // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart
  // it likely won't be a problem anyone runs into.
  const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
  if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)
    return false;
  return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true, false);
}

bool MenuItemNoCheck(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  ImGuiStyle& style = g.Style;
  ImVec2 pos = window->DC.CursorPos;
  ImVec2 label_size = CalcTextSize(label, NULL, true);

  // See BeginMenuEx() for comments about this.
  const bool menuset_is_open = IsRootOfOpenMenuSet();
  if (menuset_is_open)
    PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true);

  // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73),
  // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only.
  bool pressed;
  PushID(label);
  if (!enabled)
    BeginDisabled();

  // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
  const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
  const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) {
    // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
    // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark.
    float w = label_size.x;
    window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
    ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
    PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f);
    pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f));
    PopStyleVar();
    if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
      RenderText(text_pos, label);
    window->DC.CursorPos.x +=
        IM_TRUNC(style.ItemSpacing.x *
                 (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
  } else {
    // Menu item inside a vertical menu
    // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
    //  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.
    float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
    float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f;
    float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.f, 0.f); // Feedback for next frame
    float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
    window->DC.MenuColumns.OffsetMark = window->DC.MenuColumns.OffsetShortcut;
    pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
    if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) {
      RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
      if (icon_w > 0.0f)
        RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
      if (shortcut_w > 0.0f) {
        // PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
        LogSetNextTextDecoration("(", ")");
        RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false);
        // PopStyleColor();
      }
    }
  }
  IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
  if (!enabled)
    EndDisabled();
  PopID();
  if (menuset_is_open)
    PopItemFlag();

  return pressed;
}

float GetMinimumPanelHeight() { return (GetFrameHeight() + ImGui::GetStyle().WindowPadding.y + ImGui::GetStyle().ItemSpacing.y); }

bool SizeableCheckbox(const char* label, bool* v, float height) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  const ImGuiStyle& style = g.Style;
  const ImGuiID id = window->GetID(label);
  const ImVec2 label_size = CalcTextSize(label, NULL, true);

  const float square_sz = height > 0.f ? height : GetFrameHeight();
  const ImVec2 pos = window->DC.CursorPos;
  const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
  ItemSize(total_bb, style.FramePadding.y);
  const bool is_visible = ItemAdd(total_bb, id);
  const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0;
  if (!is_visible)
    if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(total_bb)) // Extra layer of "no logic clip" for box-select support
    {
      IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
      return false;
    }

  // Range-Selection/Multi-selection support (header)
  bool checked = *v;
  if (is_multi_select)
    MultiSelectItemHeader(id, &checked, NULL);

  bool hovered, held;
  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);

  // Range-Selection/Multi-selection support (footer)
  if (is_multi_select)
    MultiSelectItemFooter(id, &checked, &pressed);
  else if (pressed)
    checked = !checked;

  if (*v != checked) {
    *v = checked;
    pressed = true; // return value
    MarkItemEdited(id);
  }

  ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
  const float left = ImMax(square_sz / 2, GetFrameHeight() / 2);
  const float right = ImMin(square_sz / 2, GetFrameHeight() / 2);
  check_bb.Min.y += left - right;
  check_bb.Max.y += left - right;
  const bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0;
  if (is_visible) {
    RenderNavCursor(total_bb, id);
    RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
    ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
    if (mixed_value) {
      // Undocumented tristate/mixed/indeterminate checkbox (#2644)
      // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)
      ImVec2 pad(ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)), ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)));
      window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
    } else if (*v) {
      const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f));
      RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
    }
  }
  check_bb.Min.y -= left - right;
  check_bb.Max.y -= left - right;
  const ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
  if (g.LogEnabled)
    LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]");
  if (is_visible && label_size.x > 0.0f)
    RenderText(label_pos, label);

  IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
  return pressed;
}

bool BeginGroupBox(const char* label, const ImVec2& size, bool* selected, bool* clicked, const ImGuiChildFlags child_flags, const ImGuiWindowFlags window_flags) {
  ImVec2 realSize = size;
  char idString[4096];
  snprintf(idString, 4096, "%s_checkbox", label);
  auto id = GetID(label);
  auto labelId = GetID(idString);
  auto groupPos = GetCursorScreenPos();
  auto groupStart = groupPos;
  PushStyleVarY(ImGuiStyleVar_FramePadding, GetStyle().FramePadding.y * 0.5);
  groupPos.y += (GetFontSize() / 2) + GetStyle().ItemSpacing.y;
  SetCursorScreenPos(groupPos);
  groupPos.y += (GetFrameHeight() / 2);

  /* Pad the size to fit the header */
  bool fillRegion = false;
  if (size.x >= 0.f) {
    realSize.x += GetStyle().FramePadding.x + GetStyle().FrameBorderSize + GetStyle().WindowPadding.x;
  } else if (size.x <= -1.f) {
    realSize.x = (GetFontSize() / 2) + GetStyle().FrameBorderSize;
    fillRegion = true;
  }

  if (size.y >= 0.f) {
    realSize.y += (GetFontSize() / 2) + GetFrameHeight();
  } else if (size.y <= -1.f) {
    realSize.y = (GetFontSize() / 2) + GetFrameHeight();
    fillRegion = true;
  }
  PopStyleVar();

  if (clicked) {
    *clicked = false;
  }

  const auto visible = BeginChild(id, fillRegion ? size : realSize, child_flags | ImGuiChildFlags_FrameStyle, window_flags);
  if (visible) {}

  BeginDisabled(selected && !*selected);
  return visible;
}

void EndGroupBox() {
  EndDisabled();
  EndChild();
}

void ItemLabel(const char* title, const ImGuiItemLabelFlags flags) {
  ImGuiWindow* window = GetCurrentWindow();
  const ImVec2 lineStart = GetCursorScreenPos();
  const ImGuiStyle& style = GetStyle();
  float fullWidth = GetContentRegionAvail().x;
  float itemWidth = CalcItemWidth() + style.ItemSpacing.x;
  ImVec2 textSize = CalcTextSize(title);
  ImRect textRect;
  textRect.Min = ImGui::GetCursorScreenPos();
  if (flags & ImGuiItemLabelFlags_Right)
    textRect.Min.x = textRect.Min.x + itemWidth;
  textRect.Max = textRect.Min;
  textRect.Max.x += fullWidth - itemWidth;
  textRect.Max.y += textSize.y;

  SetCursorScreenPos(textRect.Min);

  AlignTextToFramePadding();
  // Adjust text rect manually because we render it directly into a drawlist instead of using public functions.
  textRect.Min.y += window->DC.CurrLineTextBaseOffset;
  textRect.Max.y += window->DC.CurrLineTextBaseOffset;

  ItemSize(textRect);
  if (ItemAdd(textRect, window->GetID(title))) {
    RenderTextEllipsis(ImGui::GetWindowDrawList(), textRect.Min, textRect.Max, textRect.Max.x, title, nullptr, &textSize);

    if (textRect.GetWidth() < textSize.x && ImGui::IsItemHovered())
      ImGui::SetTooltip("%s", title);
  }
  if (flags & ImGuiItemLabelFlags_Left) {
    SetCursorScreenPos(textRect.Max - ImVec2{0, textSize.y + window->DC.CurrLineTextBaseOffset});
    SameLine();
  } else if (flags & ImGuiItemLabelFlags_Right)
    SetCursorScreenPos(lineStart);
}

bool InputIntFormat(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags, const char* fmt) {
  // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
  const char* format = fmt != nullptr ? fmt : (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
  return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags);
}

bool SpinScaler(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) {
  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  ImGuiStyle& style = g.Style;
  IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) ==
            0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()!

  if (format == NULL)
    format = DataTypeGetInfo(data_type)->PrintFmt;

  void* p_data_default = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue;

  char buf[64];
  if ((flags & ImGuiInputTextFlags_DisplayEmptyRefVal) && DataTypeCompare(data_type, p_data, p_data_default) == 0)
    buf[0] = 0;
  else
    DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);

  // Disable the MarkItemEdited() call in InputText but keep ImGuiItemStatusFlags_Edited.
  // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
  g.NextItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited;
  flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint;

  bool value_changed = false;
  if (p_step == NULL) {
    if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
      value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL);
  } else {
    BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
    PushID(label);
    SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - ((GetFrameHeight() / 2) + GetStyle().ItemSpacing.x)));
    if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
      value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL);

    bool hovered = false; // IsItemHovered() || IsItemActive() || IsItemActiveAsInputText() || IsItemFocused();
    if (hovered && (g.IO.MouseWheel > 0.f || g.IO.MouseWheel < 0.f)) {
      if (!IsItemFocused()) {
        FocusItem();
      }
    }

    // Step buttons    // Step buttons
    const ImVec2 backup_frame_padding = style.FramePadding;
    style.FramePadding.x = style.FramePadding.y;
    if (flags & ImGuiInputTextFlags_ReadOnly) {
      hovered = false;
      BeginDisabled();
    }
    PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
    SameLine(0, style.ItemInnerSpacing.x);

    // start diffs
    float frame_height = GetFrameHeight();
    float arrow_size = std::floor(frame_height * .45f);
    float arrow_spacing = frame_height - 2.0f * arrow_size;

    BeginGroup();
    PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{g.Style.ItemSpacing.x, arrow_spacing});

    // save/change font size to draw arrow buttons correctly
    float org_font_size = GetDrawListSharedData()->FontSize;
    GetDrawListSharedData()->FontSize = arrow_size;

    if (ArrowButtonEx("+", ImGuiDir_Up, ImVec2(arrow_size, arrow_size)) || (GetIO().MouseWheel > 0 && hovered)) {
      DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
      value_changed = true;
    }

    if (ArrowButtonEx("-", ImGuiDir_Down, ImVec2(arrow_size, arrow_size)) || (GetIO().MouseWheel < 0 && hovered)) {
      DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
      value_changed = true;
    }

    PopItemFlag();
    if (flags & ImGuiInputTextFlags_ReadOnly)
      EndDisabled();

    // restore font size
    GetDrawListSharedData()->FontSize = org_font_size;

    PopStyleVar(1);
    EndGroup();
    // end diffs

    const char* label_end = FindRenderedTextEnd(label);
    if (label != label_end) {
      SameLine(0, style.ItemInnerSpacing.x);
      TextEx(label, label_end);
    }

    style.FramePadding = backup_frame_padding;

    PopID();
    EndGroup();
  }

  g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited;
  if (value_changed)
    MarkItemEdited(g.LastItemData.ID);

  return value_changed;
}

bool SpinInt(const char* label, int* v, int step, int step_fast, const char* format, ImGuiInputTextFlags flags) {
  // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
  const char* fmt = format ? format : (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
  return SpinScaler(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), fmt, flags);
}

bool SpinFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) {
  flags |= ImGuiInputTextFlags_CharsScientific;
  return SpinScaler(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags);
}

bool SpinDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) {
  flags |= ImGuiInputTextFlags_CharsScientific;
  return SpinScaler(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags);
}

bool EllipsesButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) {

  ImGuiWindow* window = GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  const ImGuiStyle& style = g.Style;
  const ImGuiID id = window->GetID(label);
  const ImVec2 label_size = CalcTextSize(label, NULL, true);

  ImVec2 pos = window->DC.CursorPos;
  if ((flags & ImGuiButtonFlags_AlignTextBaseLine) &&
      style.FramePadding.y <
          window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
    pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
  ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);

  const ImRect bb(pos, pos + size);
  ItemSize(size, style.FramePadding.y);
  if (!ItemAdd(bb, id))
    return false;

  bool hovered, held;
  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);

  // Render
  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
  RenderNavCursor(bb, id);
  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
  const char* ellipses = "\xE2\x80\xA6";
  const ImVec2 ellipses_size = CalcTextSize(ellipses);

  if (g.LogEnabled)
    LogSetNextTextDecoration("[", "]");
  ImRect bb_label = bb;
  bb_label.Max.x -= ellipses_size.x + style.FramePadding.x;
  RenderTextClipped(bb_label.Min + style.FramePadding, bb_label.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb_label);
  RenderTextClipped({bb.Max.x - (ellipses_size.x + style.FramePadding.x), bb.Min.y + style.FramePadding.y}, bb.Max - style.FramePadding, ellipses, NULL, &ellipses_size, style.ButtonTextAlign, &bb);

  // Automatically close popups
  // if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
  //    CloseCurrentPopup();

  IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
  return pressed;
}

bool EllipsesButton(const char* label, const ImVec2& size_arg) { return EllipsesButtonEx(label, size_arg, ImGuiButtonFlags_None); }

} // namespace ImGui


code:
#pragma once
#include "imgui.h"
#include <string>
#include <vector>

enum ImGuiItemLabelFlags {
  ImGuiItemLabelFlags_Left = 1u << 0u,
  ImGuiItemLabelFlags_Right = 1u << 1u,
  ImGuiItemLabelFlags_Default = ImGuiItemLabelFlags_Left,
};

namespace ImGui {
void BeginGroupPanel(const char* name = "", const ImVec2& size = ImVec2(-1.0f, -1.0f));
void EndGroupPanel();
bool LabelOverLineEdit(const char* id, const char* label, char* string, int len, float width, const char* tooltip = nullptr, ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue);

/* Copy of ImGui::Selectable with borders enabled */
bool SelectableWithBorder(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0));

void ActionTooltip(const char* action, const char* fmt, ...);

int ButtonGroup(const char* id, const std::vector<std::string>& buttons, bool isVertical = false, const std::vector<std::string>& tooltips = {});

ImVec2 GetDPIScaledSize(const ImVec2& size);
inline ImVec2 GetDPIScaledSize(const float w, const float h) { return GetDPIScaledSize(ImVec2(w, h)); }

float GetDPIScaledValue(float value);
bool MenuItemNoCheck(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true);

float GetMinimumPanelHeight();
bool SizeableCheckbox(const char* label, bool* v, float height = 0);
bool BeginGroupBox(const char* label, const ImVec2& size = {0, 0}, bool* selected = nullptr, bool* clicked = nullptr, ImGuiChildFlags child_flags = 0, ImGuiWindowFlags window_flags = 0);
void EndGroupBox();

void ItemLabel(const char* title, ImGuiItemLabelFlags flags = ImGuiItemLabelFlags_Default);
bool InputIntFormat(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0, const char* fmt = nullptr);
bool SpinScaler(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags);
bool SpinInt(const char* label, int* v, int step = 1, int step_fast = 100, const char* fmt = nullptr, ImGuiInputTextFlags flags = 0);
bool SpinFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
bool SpinDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0);
bool EllipsesButtonEx(const char* label, const ImVec2& size_arg = {0, 0}, ImGuiButtonFlags flags = 0);
bool EllipsesButton(const char* label, const ImVec2& size_arg = {0, 0});
} // namespace ImGui


code:
MIT License

Copyright (c) 2022 Simon Altschuler

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


code:
Copyright (c) 2022 Matěj Vrba

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


code:
#include "Core/ImGuiExt/TextParser.hpp"

#include <iostream>
#include <regex>
#include <stack>
#include <string>

namespace ImGui {
struct Color {
  uint8_t r = 255;
  uint8_t g = 255;
  uint8_t b = 255;
  uint8_t a = 255;
};
std::stack<Color> colors;

bool BeginsWith(const char* str, const int len, const char* other) {
  for (int i = 0; i < len; ++i, ++str, ++other) {
    if (*str != *other) {
      return false;
    }
  }
  return true;
}

uint32_t FromHex(char ch) {
  if (ch >= '0' && ch <= '9')
    return ch - '0';

  if (ch >= 'A' && ch <= 'F')
    return ch - 'A' + 10;

  if (ch >= 'a' && ch <= 'f')
    return ch - 'a' + 10;

  return 0;
}

uint8_t GetColorValue(const char* str) { return (FromHex(str[0]) << 4) + FromHex(str[1]); }

Color _ParseColor(const char* s, const int len) {
  Color color;
  color.r = GetColorValue(s + 1);
  color.g = GetColorValue(s + 3);
  color.b = GetColorValue(s + 5);
  color.a = 0xff;
  if (len == 9) {
    color.a = GetColorValue(s + 5);
  }
  return color;
}

bool ParseColor(const char* s, ImU32* col, int* skipChars) {
  if (colors.size() < 1) {
    Color tmp;
    *reinterpret_cast<int*>(&tmp.r) = GetColorU32(ImGuiCol_Text);
    colors.push(tmp);
  }

  std::string inputString{s};
  std::string token;
  std::string value;
  if (s[0] == '&') {
    bool parsed = false;
    int len = 1;
    bool foundEnd = false;
    while (s[len] != ';' && s[len] != '\0') {
      if (s[len + 1] != '\0' && s[len + 1] == ';') {
        foundEnd = true;
      }
      len++;
    }
    if (!foundEnd) {
      return false;
    }
    ++s;

    if (BeginsWith(s, 11, "push-color=")) {
      Color color = _ParseColor(s + 11, len - 11);
      *col = *reinterpret_cast<int*>(&color.r);
      colors.push(color);
      parsed = true;
    } else if (BeginsWith(s, 6, "color=")) {
      Color color = _ParseColor(s + 6, len - 6);
      *col = *reinterpret_cast<int*>(&color.r);
      parsed = true;
    } else if (BeginsWith(s, 9, "pop-color")) {
      if (colors.size() > 1) {
        colors.pop();
      }
      Color tmp = colors.top();
      *col = *reinterpret_cast<int*>(&tmp.r);
      parsed = true;
    }
    if (parsed) {
      *skipChars = len + 1;
      return true;
    }
  }
  return false;
}

ImU32 ParseGetCurrentColor() {
  if (colors.size() < 1) {
    Color col;
    *reinterpret_cast<int*>(&col.r) = GetColorU32(ImGuiCol_Text);
    colors.push(col);
  }

  Color color = colors.top();
  return *reinterpret_cast<int*>(&color.r);
}

int ParseGetStackSize() { return colors.size(); }
} // namespace ImGui


code:
#pragma once

#include "imgui.h"

namespace ImGui {
bool ParseColor(const char* s, ImU32* col, int* skipChars);
ImU32 ParseGetCurrentColor();
int ParseGetStackSize();
} // namespace ImGui


code:
#include "imgui-knobs.h"

#include <cmath>
#include <cstdlib>
#include <imgui.h>
#include <imgui_internal.h>

#define IMGUIKNOBS_PI 3.14159265358979323846f

static inline float ImLog(int x) { return ImLog(static_cast<float>(x)); }

namespace ImGuiKnobs {
namespace detail {
void draw_arc(ImVec2 center, float radius, float start_angle, float end_angle, float thickness, ImColor color) {
  auto* draw_list = ImGui::GetWindowDrawList();

  draw_list->PathArcTo(center, radius, start_angle, end_angle);
  draw_list->PathStroke(color, 0, thickness);
}

template <typename DataType>
struct knob {
  float radius;
  bool value_changed;
  ImVec2 center;
  bool is_active;
  bool is_hovered;
  float angle_min;
  float angle_max;
  float t;
  float angle;
  float angle_cos;
  float angle_sin;

  knob(const char* _label, ImGuiDataType data_type, DataType* p_value, DataType v_min, DataType v_max, float speed, float _radius, const char* format, ImGuiKnobFlags flags, float _angle_min,
       float _angle_max) {
    radius = _radius;
    if (flags & ImGuiKnobFlags_Logarithmic) {
      float v = ImMax(ImMin(*p_value, v_max), v_min);
      t = (ImLog(ImAbs(v)) - ImLog(ImAbs(v_min))) / (ImLog(ImAbs(v_max)) - ImLog(ImAbs(v_min)));
    } else {
      t = ((float)*p_value - v_min) / (v_max - v_min);
    }
    auto screen_pos = ImGui::GetCursorScreenPos();

    // Handle dragging
    ImGui::InvisibleButton(_label, {radius * 2.0f, radius * 2.0f});

    // Handle drag: if DragVertical or DragHorizontal flags are set, only the given direction is
    // used, otherwise use the drag direction with the highest delta
    ImGuiIO& io = ImGui::GetIO();
    bool drag_vertical = !(flags & ImGuiKnobFlags_DragHorizontal) && (flags & ImGuiKnobFlags_DragVertical || ImAbs(io.MouseDelta[ImGuiAxis_Y]) > ImAbs(io.MouseDelta[ImGuiAxis_X]));

    auto gid = ImGui::GetID(_label);
    ImGuiSliderFlags drag_behaviour_flags = 0;
    if (drag_vertical) {
      drag_behaviour_flags |= ImGuiSliderFlags_Vertical;
    }
    if (flags & ImGuiKnobFlags_AlwaysClamp) {
      drag_behaviour_flags |= ImGuiSliderFlags_AlwaysClamp;
    }
    if (flags & ImGuiKnobFlags_Logarithmic) {
      drag_behaviour_flags |= ImGuiSliderFlags_Logarithmic;
    }
    value_changed = ImGui::DragBehavior(gid, data_type, p_value, speed, &v_min, &v_max, format, drag_behaviour_flags);

    angle_min = _angle_min < 0 ? IMGUIKNOBS_PI * 0.75f : _angle_min;
    angle_max = _angle_max < 0 ? IMGUIKNOBS_PI * 2.25f : _angle_max;

    center = {screen_pos[0] + radius, screen_pos[1] + radius};
    is_active = ImGui::IsItemActive();
    is_hovered = ImGui::IsItemHovered();
    angle = angle_min + (angle_max - angle_min) * t;
    angle_cos = cosf(angle);
    angle_sin = sinf(angle);
  }

  void draw_dot(float size, float radius, float angle, color_set color, bool filled, int segments) {
    auto dot_size = size * this->radius;
    auto dot_radius = radius * this->radius;

    ImGui::GetWindowDrawList()->AddCircleFilled({center[0] + cosf(angle) * dot_radius, center[1] + sinf(angle) * dot_radius}, dot_size,
                                                is_active ? color.active : (is_hovered ? color.hovered : color.base), segments);
  }

  void draw_tick(float start, float end, float width, float angle, color_set color) {
    auto tick_start = start * radius;
    auto tick_end = end * radius;
    auto angle_cos = cosf(angle);
    auto angle_sin = sinf(angle);

    ImGui::GetWindowDrawList()->AddLine({center[0] + angle_cos * tick_end, center[1] + angle_sin * tick_end}, {center[0] + angle_cos * tick_start, center[1] + angle_sin * tick_start},
                                        is_active ? color.active : (is_hovered ? color.hovered : color.base), width * radius);
  }

  void draw_circle(float size, color_set color, bool filled, int segments) {
    auto circle_radius = size * radius;

    ImGui::GetWindowDrawList()->AddCircleFilled(center, circle_radius, is_active ? color.active : (is_hovered ? color.hovered : color.base));
  }

  void draw_arc(float radius, float size, float start_angle, float end_angle, color_set color) {
    auto track_radius = radius * this->radius;
    auto track_size = size * this->radius * 0.5f + 0.0001f;

    detail::draw_arc(center, track_radius, start_angle, end_angle, track_size, is_active ? color.active : (is_hovered ? color.hovered : color.base));
  }
};

template <typename DataType>
knob<DataType> knob_with_drag(const char* label, ImGuiDataType data_type, DataType* p_value, DataType v_min, DataType v_max, float _speed, const char* format, float size, ImGuiKnobFlags flags,
                              float angle_min, float angle_max) {
  if (flags & ImGuiKnobFlags_Logarithmic && v_min <= 0.0 && v_max >= 0.0) {
    // we must handle the cornercase if a client specifies a logarithmic range that contains zero
    // for this we clamp lower limit to avoid hitting zero like it is done in ImGui::SliderBehaviorT
    const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
    const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1;
    v_min = ImPow(0.1f, (float)decimal_precision);
    v_max = ImMax(v_min, v_max);                     // this ensures that in the cornercase v_max is still at least ge v_min
    *p_value = ImMax(ImMin(*p_value, v_max), v_min); // this ensures that in the cornercase p_value is within the range
  }

  auto speed = _speed == 0 ? (v_max - v_min) / 250.f : _speed;
  ImGui::PushID(label);
  auto width = size == 0 ? ImGui::GetTextLineHeight() * 4.0f : size * ImGui::GetIO().FontGlobalScale;
  ImGui::PushItemWidth(width);

  ImGui::BeginGroup();

  // There's an issue with `SameLine` and Groups, see
  // https://github.com/ocornut/imgui/issues/4190. This is probably not the best
  // solution, but seems to work for now
  ImGui::GetCurrentWindow()->DC.CurrLineTextBaseOffset = 0;

  // Draw title
  if (!(flags & ImGuiKnobFlags_NoTitle)) {
    auto title_size = ImGui::CalcTextSize(label, NULL, false, width);

    // Center title
    ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (width - title_size[0]) * 0.5f);

    ImGui::Text("%s", label);
  }

  // Draw knob
  knob<DataType> k(label, data_type, p_value, v_min, v_max, speed, width * 0.5f, format, flags, angle_min, angle_max);

  // Draw tooltip
  if (flags & ImGuiKnobFlags_ValueTooltip && (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) || ImGui::IsItemActive())) {
    ImGui::BeginTooltip();
    ImGui::Text(format, *p_value);
    ImGui::EndTooltip();
  }

  // Draw input
  if (!(flags & ImGuiKnobFlags_NoInput)) {
    ImGuiSliderFlags drag_scalar_flags = 0;
    if (flags & ImGuiKnobFlags_AlwaysClamp) {
      drag_scalar_flags |= ImGuiSliderFlags_AlwaysClamp;
    }
    if (flags & ImGuiKnobFlags_Logarithmic) {
      drag_scalar_flags |= ImGuiSliderFlags_Logarithmic;
    }
    auto changed = ImGui::DragScalar("###knob_drag", data_type, p_value, speed, &v_min, &v_max, format, drag_scalar_flags);
    if (changed) {
      k.value_changed = true;
    }
  }

  ImGui::EndGroup();
  ImGui::PopItemWidth();
  ImGui::PopID();

  return k;
}

color_set GetPrimaryColorSet() {
  auto* colors = ImGui::GetStyle().Colors;

  return {colors[ImGuiCol_ButtonActive], colors[ImGuiCol_ButtonHovered], colors[ImGuiCol_ButtonHovered]};
}

color_set GetSecondaryColorSet() {
  auto* colors = ImGui::GetStyle().Colors;
  auto active = ImVec4(colors[ImGuiCol_ButtonActive].x * 0.5f, colors[ImGuiCol_ButtonActive].y * 0.5f, colors[ImGuiCol_ButtonActive].z * 0.5f, colors[ImGuiCol_ButtonActive].w);

  auto hovered = ImVec4(colors[ImGuiCol_ButtonHovered].x * 0.5f, colors[ImGuiCol_ButtonHovered].y * 0.5f, colors[ImGuiCol_ButtonHovered].z * 0.5f, colors[ImGuiCol_ButtonHovered].w);

  return {active, hovered, hovered};
}

color_set GetTrackColorSet() {
  auto* colors = ImGui::GetStyle().Colors;

  return {colors[ImGuiCol_Button], colors[ImGuiCol_Button], colors[ImGuiCol_Button]};
}
} // namespace detail

template <typename DataType>
bool BaseKnob(const char* label, ImGuiDataType data_type, DataType* p_value, DataType v_min, DataType v_max, float speed, const char* format, ImGuiKnobVariant variant, float size,
              ImGuiKnobFlags flags, int steps, float angle_min, float angle_max) {
  auto knob = detail::knob_with_drag(label, data_type, p_value, v_min, v_max, speed, format, size, flags, angle_min, angle_max);

  switch (variant) {
  case ImGuiKnobVariant_Tick: {
    knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
    knob.draw_tick(0.5f, 0.85f, 0.08f, knob.angle, detail::GetPrimaryColorSet());
    break;
  }
  case ImGuiKnobVariant_Dot: {
    knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
    knob.draw_dot(0.12f, 0.6f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
    break;
  }

  case ImGuiKnobVariant_Wiper: {
    knob.draw_circle(0.7f, detail::GetSecondaryColorSet(), true, 32);
    knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());

    if (knob.t > 0.01f) {
      knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet());
    }
    break;
  }
  case ImGuiKnobVariant_WiperOnly: {
    knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());

    if (knob.t > 0.01) {
      knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet());
    }
    break;
  }
  case ImGuiKnobVariant_WiperDot: {
    knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
    knob.draw_arc(0.85f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());
    knob.draw_dot(0.1f, 0.85f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
    break;
  }
  case ImGuiKnobVariant_Stepped: {
    for (auto n = 0.f; n < steps; n++) {
      auto a = n / (steps - 1);
      auto angle = knob.angle_min + (knob.angle_max - knob.angle_min) * a;
      knob.draw_tick(0.7f, 0.9f, 0.04f, angle, detail::GetPrimaryColorSet());
    }

    knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
    knob.draw_dot(0.12f, 0.4f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
    break;
  }
  case ImGuiKnobVariant_Space: {
    knob.draw_circle(0.3f - knob.t * 0.1f, detail::GetSecondaryColorSet(), true, 16);

    if (knob.t > 0.01f) {
      knob.draw_arc(0.4f, 0.15f, knob.angle_min - 1.0f, knob.angle - 1.0f, detail::GetPrimaryColorSet());
      knob.draw_arc(0.6f, 0.15f, knob.angle_min + 1.0f, knob.angle + 1.0f, detail::GetPrimaryColorSet());
      knob.draw_arc(0.8f, 0.15f, knob.angle_min + 3.0f, knob.angle + 3.0f, detail::GetPrimaryColorSet());
    }
    break;
  }
  }

  return knob.value_changed;
}

bool Knob(const char* label, float* p_value, float v_min, float v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min,
          float angle_max) {
  return BaseKnob(label, ImGuiDataType_Float, p_value, v_min, v_max, speed, format, variant, size, flags, steps, angle_min, angle_max);
}

bool KnobInt(const char* label, int* p_value, int v_min, int v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min,
             float angle_max) {
  return BaseKnob(label, ImGuiDataType_S32, p_value, v_min, v_max, speed, format, variant, size, flags, steps, angle_min, angle_max);
}
} // namespace ImGuiKnobs


code:
#pragma once

#include <cstdlib>
#include <imgui.h>

typedef int ImGuiKnobFlags;

enum ImGuiKnobFlags_ {
  ImGuiKnobFlags_NoTitle = 1 << 0,
  ImGuiKnobFlags_NoInput = 1 << 1,
  ImGuiKnobFlags_ValueTooltip = 1 << 2,
  ImGuiKnobFlags_DragHorizontal = 1 << 3,
  ImGuiKnobFlags_DragVertical = 1 << 4,
  ImGuiKnobFlags_Logarithmic = 1 << 5,
  ImGuiKnobFlags_AlwaysClamp = 1 << 6
};

typedef int ImGuiKnobVariant;

enum ImGuiKnobVariant_ {
  ImGuiKnobVariant_Tick = 1 << 0,
  ImGuiKnobVariant_Dot = 1 << 1,
  ImGuiKnobVariant_Wiper = 1 << 2,
  ImGuiKnobVariant_WiperOnly = 1 << 3,
  ImGuiKnobVariant_WiperDot = 1 << 4,
  ImGuiKnobVariant_Stepped = 1 << 5,
  ImGuiKnobVariant_Space = 1 << 6,
};

namespace ImGuiKnobs {

struct color_set {
  ImColor base;
  ImColor hovered;
  ImColor active;

  color_set(ImColor base, ImColor hovered, ImColor active)
      : base(base), hovered(hovered), active(active) {}

  color_set(ImColor color) {
    base = color;
    hovered = color;
    active = color;
  }
};

bool Knob(
        const char *label,
        float *p_value,
        float v_min,
        float v_max,
        float speed = 0,
        const char *format = "%.3f",
        ImGuiKnobVariant variant = ImGuiKnobVariant_Tick,
        float size = 0,
        ImGuiKnobFlags flags = 0,
        int steps = 10,
        float angle_min = -1,
        float angle_max = -1);
bool KnobInt(
        const char *label,
        int *p_value,
        int v_min,
        int v_max,
        float speed = 0,
        const char *format = "%i",
        ImGuiKnobVariant variant = ImGuiKnobVariant_Tick,
        float size = 0,
        ImGuiKnobFlags flags = 0,
        int steps = 10,
        float angle_min = -1,
        float angle_max = -1);

}// namespace ImGuiKnobs


code:
//
// Created by Matty on 2022-01-28.
//

#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif

#include "imgui_neo_internal.h"
#include "imgui_internal.h"
#include <cstdint>

namespace ImGui {
void RenderNeoSequencerBackground(const ImVec4& color, const ImVec2& cursor, const ImVec2& size, ImDrawList* drawList, float sequencerRounding) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  const ImRect area = {cursor, cursor + size};

  drawList->AddRectFilled(area.Min, area.Max, ColorConvertFloat4ToU32(color), sequencerRounding);
}

void RenderNeoSequencerTopBarBackground(const ImVec4& color, const ImVec2& cursor, const ImVec2& size, ImDrawList* drawList, float sequencerRounding) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  const ImRect barArea = {cursor, cursor + size};

  drawList->AddRectFilled(barArea.Min, barArea.Max, ColorConvertFloat4ToU32(color), sequencerRounding);
}

void RenderNeoSequencerTopBarOverlay(float zoom, float valuesWidth, uint32_t startFrame, uint32_t endFrame, uint32_t offsetFrame, const ImVec2& cursor, const ImVec2& size, ImDrawList* drawList,
                                     bool drawFrameLines, bool drawFrameText, float maxPixelsPerTick) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  const auto& style = GetStyle();

  const ImRect barArea = {cursor + ImVec2{style.FramePadding.x + valuesWidth, style.FramePadding.y}, cursor + size};

  const uint32_t viewEnd = endFrame + offsetFrame;
  const uint32_t viewStart = startFrame + offsetFrame;

  if (drawFrameLines) {
    const auto count = (int32_t)((float)((viewEnd + 1) - viewStart) / zoom);

    int32_t counter = 0;
    uint32_t primaryFrames = pow(10, counter++);
    uint32_t secondaryFrames = pow(10, counter);

    float perFrameWidth = GetPerFrameWidth(size.x, valuesWidth, endFrame, startFrame, zoom);

    if (perFrameWidth <= 0.0f)
      return;

    while (perFrameWidth < maxPixelsPerTick) {
      primaryFrames = pow(10, counter++);
      secondaryFrames = pow(10, counter);

      perFrameWidth *= (float)primaryFrames;
    }

    if (primaryFrames == 0 || secondaryFrames == 0) {
      primaryFrames = 1;
      secondaryFrames = 10;
    }

    for (int32_t i = 0; i < count; i++) {

      const auto primaryFrame = ((viewStart + i) % primaryFrames == 0);
      const auto secondaryFrame = ((viewStart + i) % secondaryFrames == 0);

      if (!primaryFrame && !secondaryFrame)
        continue;

      const auto lineHeight = secondaryFrame ? barArea.GetSize().y : barArea.GetSize().y / 2.0f;

      const ImVec2 p1 = {barArea.Min.x + (float)i * (perFrameWidth / (float)primaryFrames), barArea.Max.y};
      const ImVec2 p2 = {barArea.Min.x + (float)i * (perFrameWidth / (float)primaryFrames), barArea.Max.y - lineHeight};

      drawList->AddLine(p1, p2, IM_COL32_WHITE, 1.0f);

      if (drawFrameText && secondaryFrame) {
        char text[10];
        const auto printRes = snprintf(text, sizeof(text), "%i", viewStart + i);
        if (printRes > 0) {
          drawList->AddText(NULL, 0, {p1.x + 2.0f, barArea.Min.y}, IM_COL32_WHITE, text);
        }
      }
    }
  }
}

void RenderNeoTimelineLabel(const char* label, const ImVec2& cursor, const ImVec2& size, const ImVec4& color, bool isGroup, bool isOpen, ImDrawList* drawList) {
  const auto& imStyle = GetStyle();

  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  auto c = cursor;

  if (isGroup) {
    RenderArrow(drawList, c, IM_COL32_WHITE, isOpen ? ImGuiDir_Down : ImGuiDir_Right);
    c.x += size.y + imStyle.ItemSpacing.x;
  }

  drawList->AddText(c, ColorConvertFloat4ToU32(color), label, FindRenderedTextEnd(label));
}

void RenderNeoTimelinesBorder(const ImVec4& color, const ImVec2& cursor, const ImVec2& size, ImDrawList* drawList, float rounding, float borderSize) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  drawList->AddRect(cursor, cursor + size, ColorConvertFloat4ToU32(color), rounding, 0, borderSize);
}

void RenderNeoTimelane(bool selected, const ImVec2& cursor, const ImVec2& size, const ImVec4& highlightColor, ImDrawList* drawList) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  if (selected) {
    const ImRect area = {cursor, cursor + size};
    drawList->AddRectFilled(area.Min, area.Max, ColorConvertFloat4ToU32(highlightColor));
  }
}

float GetPerFrameWidth(float totalSizeX, float valuesWidth, uint32_t endFrame, uint32_t startFrame, float zoom) {
  const auto& imStyle = GetStyle();

  const auto size = totalSizeX - valuesWidth - imStyle.FramePadding.x;

  auto count = (endFrame + 1) - startFrame;

  return ((size / (float)count) * zoom);
}

struct Vec2Pair {
  ImVec2 a;
  ImVec2 b;
};

static Vec2Pair getCurrentFrameLine(const ImRect& pointerBB, float timelineHeight) {
  const auto center = ImVec2{pointerBB.Min.x, pointerBB.Max.y} + ImVec2{pointerBB.GetSize().x / 2.0f, 0};

  return Vec2Pair{center, center + ImVec2{0, timelineHeight}};
}

void RenderNeoSequencerCurrentFrame(const ImVec4& color, const ImVec4& topColor, const ImRect& pointerBB, float timelineHeight, float lineWidth, ImDrawList* drawList) {
  if (!drawList)
    drawList = ImGui::GetWindowDrawList();

  const auto pair = getCurrentFrameLine(pointerBB, timelineHeight);

  drawList->AddLine(pair.a, pair.b, ColorConvertFloat4ToU32(color), lineWidth);

  drawList->PopClipRect();

  { // Top pointer has custom shape, we have to create it
    const auto size = pointerBB.GetSize();
    ImVec2 pts[5];
    pts[0] = pointerBB.Min;
    pts[1] = pointerBB.Min + ImVec2{size.x, 0};
    pts[2] = pointerBB.Min + ImVec2{size.x, size.y * 0.85f};
    pts[3] = pointerBB.Min + ImVec2{size.x / 2, size.y};
    pts[4] = pointerBB.Min + ImVec2{0, size.y * 0.85f};

    drawList->AddConvexPolyFilled(pts, sizeof(pts) / sizeof(*pts), ColorConvertFloat4ToU32(topColor));
  }
}
} // namespace ImGui


code:
//
// Created by Matty on 2022-01-28.
//

#ifndef IMGUI_NEO_INTERNAL_H
#define IMGUI_NEO_INTERNAL_H

#include "imgui.h"
#include "imgui_internal.h"
#include <cstdint>

namespace ImGui {
    IMGUI_API void  RenderNeoSequencerBackground(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float sequencerRounding = 0.0f);
    IMGUI_API void  RenderNeoSequencerTopBarBackground(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float sequencerRounding = 0.0f);
    IMGUI_API void  RenderNeoSequencerTopBarOverlay(float zoom, float valuesWidth,uint32_t startFrame, uint32_t endFrame, uint32_t offsetFrame, const ImVec2 &cursor, const ImVec2& size, ImDrawList * drawList = nullptr, bool drawFrameLines = true, bool drawFrameText = true, float maxPixelsPerTick = -1.0f);
    IMGUI_API void  RenderNeoTimelineLabel(const char * label,const ImVec2 & cursor,const ImVec2 & size, const ImVec4& color,bool isGroup = false, bool isOpen = false, ImDrawList *drawList = nullptr );
    IMGUI_API void  RenderNeoTimelane(bool selected,const ImVec2 & cursor, const ImVec2& size, const ImVec4& highlightColor, ImDrawList *drawList = nullptr);
    IMGUI_API void  RenderNeoTimelinesBorder(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float rounding = 0.0f, float borderSize = 1.0f);
    IMGUI_API void  RenderNeoSequencerCurrentFrame(const ImVec4& color,const ImVec4 & topColor,const ImRect & pointerBB ,float timelineHeight, float lineWidth = 1.0f, ImDrawList * drawList = nullptr);

    IMGUI_API float GetPerFrameWidth(float totalSizeX, float valuesWidth, uint32_t endFrame, uint32_t startFrame, float zoom);
}

#endif //IMGUI_NEO_INTERNAL_H