134{
  135  int res = -1;
  136  ssize_t LastActiveTextInput = -1;
  137  ssize_t CurrentActiveTextInput = next(-1);
  138 
  139  if (!_window || !_renderer)
  140    return -2;
  141 
  142  try
  143  {
  144    bool running = true;
  145    std::vector<SDL_Keycode> pressed;
  146    while (running)
  147    {
  148      if (!clear_window(_renderer))
  149        throw;
  150 
  151      if (!update(_renderer))
  152        throw;
  153 
  154      if (!_buttons.update(_renderer))
  155        throw;
  156 
  157      SDL_Event event = {};
  158      SDL_WaitEvent(&event);
  159      switch (event.type)
  160      {
  161        case SDL_KEYUP:
  162        {
  163          auto it = std::remove(pressed.begin(), pressed.end(), event.key.keysym.sym);
  164          pressed.erase(it, pressed.end());
  165 
  166          switch (event.key.keysym.sym)
  167          {
  168            case SDLK_BACKSPACE:
  169            {
  170              auto cur = get(CurrentActiveTextInput);
  171              if (cur)
  172              {
  173                if (!cur->remove_str(_renderer, 1))
  174                  throw;
  175              }
  176            }
  177            break;
  178            case SDLK_TAB:
  179              CurrentActiveTextInput = next(CurrentActiveTextInput);
  180              break;
  181            case SDLK_RETURN:
  182            case SDLK_RETURN2:
  183            case SDLK_KP_ENTER:
  184              running = false;
  185              res = INPUT_BUTTON_ACCEPT;
  186              break;
  187            case SDLK_ESCAPE:
  188              running = false;
  189              res = INPUT_BUTTON_CANCEL;
  190              break;
  191            case SDLK_v:
  192              if (pressed.size() == 2)
  193              {
  194                if ((pressed[0] == SDLK_LCTRL) || (pressed[0] == SDLK_RCTRL))
  195                {
  196                  auto cur = get(CurrentActiveTextInput);
  197                  if (cur)
  198                  {
  199                    auto text = SDL_GetClipboardText();
  200                    cur->set_str(_renderer, text);
  201                  }
  202                }
  203              }
  204              break;
  205            default:
  206              break;
  207          }
  208        }
  209        break;
  210        case SDL_KEYDOWN:
  211          pressed.push_back(event.key.keysym.sym);
  212          break;
  213        case SDL_TEXTINPUT:
  214        {
  215          auto cur = get(CurrentActiveTextInput);
  216          if (cur)
  217          {
  218            if (!cur->append_str(_renderer, event.text.text))
  219              throw;
  220          }
  221        }
  222        break;
  223        case SDL_MOUSEMOTION:
  224        {
  225          auto TextInputIndex = get_index(event.button);
  226          for (auto& cur : _list)
  227          {
  228            if (!cur.set_mouseover(_renderer, false))
  229              throw;
  230          }
  231          if (TextInputIndex >= 0)
  232          {
  233            auto& cur = _list[static_cast<size_t>(TextInputIndex)];
  234            if (!cur.set_mouseover(_renderer, true))
  235              throw;
  236          }
  237 
  238          _buttons.set_mouseover(event.button.x, event.button.y);
  239        }
  240        break;
  241        case SDL_MOUSEBUTTONDOWN:
  242        {
  243          auto val = get_index(event.button);
  244          if (valid(val))
  245            CurrentActiveTextInput = val;
  246 
  247          auto button = _buttons.get_selected(event.button);
  248          if (button)
  249          {
  250            running = false;
  251            if (button->id() == INPUT_BUTTON_CANCEL)
  252              res = INPUT_BUTTON_CANCEL;
  253            else
  254              res = INPUT_BUTTON_ACCEPT;
  255          }
  256        }
  257        break;
  258        case SDL_QUIT:
  259          res = INPUT_BUTTON_CANCEL;
  260          running = false;
  261          break;
  262        default:
  263          break;
  264      }
  265 
  266      if (LastActiveTextInput != CurrentActiveTextInput)
  267      {
  268        if (CurrentActiveTextInput < 0)
  269          SDL_StopTextInput();
  270        else
  271          SDL_StartTextInput();
  272        LastActiveTextInput = CurrentActiveTextInput;
  273      }
  274 
  275      for (auto& cur : _list)
  276      {
  277        if (!cur.set_highlight(_renderer, false))
  278          throw;
  279      }
  280      auto cur = get(CurrentActiveTextInput);
  281      if (cur)
  282      {
  283        if (!cur->set_highlight(_renderer, true))
  284          throw;
  285      }
  286 
  287      SDL_RenderPresent(_renderer);
  288    }
  289 
  290    for (auto& cur : _list)
  291      result.push_back(cur.value());
  292  }
  293  catch (...)
  294  {
  295    res = -2;
  296  }
  297 
  298  return res;
  299}