6#include "sdl_input_widgets.hpp" 
    8static const Uint32 vpadding = 5;
 
   10SdlInputWidgetList::SdlInputWidgetList(
const std::string& title,
 
   11                                       const std::vector<std::string>& labels,
 
   12                                       const std::vector<std::string>& initial,
 
   13                                       const std::vector<Uint32>& flags)
 
   14    : _window(nullptr), _renderer(nullptr)
 
   16  assert(labels.size() == initial.size());
 
   17  assert(labels.size() == flags.size());
 
   18  const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
 
   19  const std::vector<std::string> buttonlabels = { 
"accept", 
"cancel" };
 
   21  const size_t widget_width = 300;
 
   22  const size_t widget_heigth = 50;
 
   24  const size_t total_width = widget_width + widget_width;
 
   25  const size_t input_height = labels.size() * (widget_heigth + vpadding) + vpadding;
 
   26  const size_t total_height = input_height + widget_heigth;
 
   28  assert(total_width <= INT32_MAX);
 
   29  assert(total_height <= INT32_MAX);
 
   30  Uint32 wflags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS;
 
   32      SDL_CreateWindowAndRenderer(
static_cast<int>(total_width), 
static_cast<int>(total_height),
 
   33                                  wflags, &_window, &_renderer);
 
   35    widget_log_error(rc, 
"SDL_CreateWindowAndRenderer");
 
   38    SDL_SetWindowTitle(_window, title.c_str());
 
   39    for (
size_t x = 0; x < labels.size(); x++)
 
   40      _list.emplace_back(_renderer, labels[x], initial[x], flags[x], x, widget_width,
 
   43    _buttons.populate(_renderer, buttonlabels, buttonids, total_width,
 
   44                      static_cast<Sint32
>(input_height), 
static_cast<Sint32
>(widget_width),
 
   45                      static_cast<Sint32
>(widget_heigth));
 
   46    _buttons.set_highlight(0);
 
   50ssize_t SdlInputWidgetList::next(ssize_t current)
 
   53  auto val = 
static_cast<size_t>(current);
 
   57    if (iteration >= _list.size())
 
   71  } 
while (!valid(
static_cast<ssize_t
>(val)));
 
   72  return static_cast<ssize_t
>(val);
 
   75bool SdlInputWidgetList::valid(ssize_t current)
 const 
   79  auto s = 
static_cast<size_t>(current);
 
   80  if (s >= _list.size())
 
   82  return !_list[s].readonly();
 
   89  auto s = 
static_cast<size_t>(index);
 
   90  if (s >= _list.size())
 
   95SdlInputWidgetList::~SdlInputWidgetList()
 
   99  SDL_DestroyRenderer(_renderer);
 
  100  SDL_DestroyWindow(_window);
 
  103bool SdlInputWidgetList::update(SDL_Renderer* renderer)
 
  105  for (
auto& btn : _list)
 
  107    if (!btn.update_label(renderer))
 
  109    if (!btn.update_input(renderer))
 
  113  return _buttons.update(renderer);
 
  116ssize_t SdlInputWidgetList::get_index(
const SDL_MouseButtonEvent& button)
 
  118  const Sint32 x = button.x;
 
  119  const Sint32 y = button.y;
 
  121  assert(_list.size() <= std::numeric_limits<ssize_t>::max());
 
  122  for (
size_t i = 0; i < _list.size(); i++)
 
  124    auto& cur = _list[i];
 
  125    auto r = cur.input_rect();
 
  127    if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
 
  128      return static_cast<ssize_t
>(i);
 
  133int SdlInputWidgetList::run(std::vector<std::string>& result)
 
  136  ssize_t LastActiveTextInput = -1;
 
  137  ssize_t CurrentActiveTextInput = next(-1);
 
  139  if (!_window || !_renderer)
 
  145    std::vector<SDL_Keycode> pressed;
 
  148      if (!clear_window(_renderer))
 
  151      if (!update(_renderer))
 
  154      if (!_buttons.update(_renderer))
 
  157      SDL_Event 
event = {};
 
  158      SDL_WaitEvent(&event);
 
  163          auto it = std::remove(pressed.begin(), pressed.end(), event.key.keysym.sym);
 
  164          pressed.erase(it, pressed.end());
 
  166          switch (event.key.keysym.sym)
 
  170              auto cur = get(CurrentActiveTextInput);
 
  173                if (!cur->remove_str(_renderer, 1))
 
  179              CurrentActiveTextInput = next(CurrentActiveTextInput);
 
  185              res = INPUT_BUTTON_ACCEPT;
 
  189              res = INPUT_BUTTON_CANCEL;
 
  192              if (pressed.size() == 2)
 
  194                if ((pressed[0] == SDLK_LCTRL) || (pressed[0] == SDLK_RCTRL))
 
  196                  auto cur = get(CurrentActiveTextInput);
 
  199                    auto text = SDL_GetClipboardText();
 
  200                    cur->set_str(_renderer, text);
 
  211          pressed.push_back(event.key.keysym.sym);
 
  215          auto cur = get(CurrentActiveTextInput);
 
  218            if (!cur->append_str(_renderer, event.text.text))
 
  223        case SDL_MOUSEMOTION:
 
  225          auto TextInputIndex = get_index(event.button);
 
  226          for (
auto& cur : _list)
 
  228            if (!cur.set_mouseover(_renderer, 
false))
 
  231          if (TextInputIndex >= 0)
 
  233            auto& cur = _list[
static_cast<size_t>(TextInputIndex)];
 
  234            if (!cur.set_mouseover(_renderer, 
true))
 
  238          _buttons.set_mouseover(event.button.x, event.button.y);
 
  241        case SDL_MOUSEBUTTONDOWN:
 
  243          auto val = get_index(event.button);
 
  245            CurrentActiveTextInput = val;
 
  247          auto button = _buttons.get_selected(event.button);
 
  251            if (button->id() == INPUT_BUTTON_CANCEL)
 
  252              res = INPUT_BUTTON_CANCEL;
 
  254              res = INPUT_BUTTON_ACCEPT;
 
  259          res = INPUT_BUTTON_CANCEL;
 
  266      if (LastActiveTextInput != CurrentActiveTextInput)
 
  268        if (CurrentActiveTextInput < 0)
 
  271          SDL_StartTextInput();
 
  272        LastActiveTextInput = CurrentActiveTextInput;
 
  275      for (
auto& cur : _list)
 
  277        if (!cur.set_highlight(_renderer, 
false))
 
  280      auto cur = get(CurrentActiveTextInput);
 
  283        if (!cur->set_highlight(_renderer, 
true))
 
  287      SDL_RenderPresent(_renderer);
 
  290    for (
auto& cur : _list)
 
  291      result.push_back(cur.value());