FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widgets.cpp
2024-08-12 11:50:02 +02:00

291 lines
6.5 KiB
C++

#include <cassert>
#include <algorithm>
#include "sdl_input_widgets.hpp"
static const Uint32 vpadding = 5;
SdlInputWidgetList::SdlInputWidgetList(const std::string& title,
const std::vector<std::string>& labels,
const std::vector<std::string>& initial,
const std::vector<Uint32>& flags)
: _window(nullptr), _renderer(nullptr)
{
assert(labels.size() == initial.size());
assert(labels.size() == flags.size());
const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
const std::vector<std::string> buttonlabels = { "accept", "cancel" };
const size_t widget_width = 300;
const size_t widget_heigth = 50;
const size_t total_width = widget_width + widget_width;
const size_t input_height = labels.size() * (widget_heigth + vpadding) + vpadding;
const size_t total_height = input_height + widget_heigth;
auto rc = SDL_CreateWindowAndRenderer(title.c_str(), total_width, total_height,
SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_MOUSE_FOCUS |
SDL_WINDOW_INPUT_FOCUS,
&_window, &_renderer);
if (rc != 0)
widget_log_error(rc, "SDL_CreateWindowAndRenderer");
else
{
for (size_t x = 0; x < labels.size(); x++)
_list.emplace_back(_renderer, labels[x], initial[x], flags[x], x, widget_width,
widget_heigth);
_buttons.populate(_renderer, buttonlabels, buttonids, total_width,
static_cast<Sint32>(input_height), static_cast<Sint32>(widget_width),
static_cast<Sint32>(widget_heigth));
_buttons.set_highlight(0);
}
}
ssize_t SdlInputWidgetList::next(ssize_t current)
{
size_t iteration = 0;
auto val = static_cast<size_t>(current);
do
{
if (iteration >= _list.size())
return -1;
if (iteration == 0)
{
if (current < 0)
val = 0;
else
val++;
}
else
val++;
iteration++;
val %= _list.size();
} while (!valid(static_cast<ssize_t>(val)));
return static_cast<ssize_t>(val);
}
bool SdlInputWidgetList::valid(ssize_t current) const
{
if (current < 0)
return false;
auto s = static_cast<size_t>(current);
if (s >= _list.size())
return false;
return !_list[s].readonly();
}
SdlInputWidget* SdlInputWidgetList::get(ssize_t index)
{
if (index < 0)
return nullptr;
auto s = static_cast<size_t>(index);
if (s >= _list.size())
return nullptr;
return &_list[s];
}
SdlInputWidgetList::~SdlInputWidgetList()
{
_list.clear();
_buttons.clear();
SDL_DestroyRenderer(_renderer);
SDL_DestroyWindow(_window);
}
bool SdlInputWidgetList::update(SDL_Renderer* renderer)
{
for (auto& btn : _list)
{
if (!btn.update_label(renderer))
return false;
if (!btn.update_input(renderer))
return false;
}
return _buttons.update(renderer);
}
ssize_t SdlInputWidgetList::get_index(const SDL_MouseButtonEvent& button)
{
const Sint32 x = button.x;
const Sint32 y = button.y;
for (size_t i = 0; i < _list.size(); i++)
{
auto& cur = _list[i];
auto r = cur.input_rect();
if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
return i;
}
return -1;
}
int SdlInputWidgetList::run(std::vector<std::string>& result)
{
int res = -1;
ssize_t LastActiveTextInput = -1;
ssize_t CurrentActiveTextInput = next(-1);
if (!_window || !_renderer)
return -2;
try
{
bool running = true;
std::vector<SDL_Keycode> pressed;
while (running)
{
if (!clear_window(_renderer))
throw;
if (!update(_renderer))
throw;
if (!_buttons.update(_renderer))
throw;
SDL_Event event = {};
SDL_WaitEvent(&event);
switch (event.type)
{
case SDL_EVENT_KEY_UP:
{
auto it = std::remove(pressed.begin(), pressed.end(), event.key.key);
pressed.erase(it, pressed.end());
switch (event.key.key)
{
case SDLK_BACKSPACE:
{
auto cur = get(CurrentActiveTextInput);
if (cur)
{
if (!cur->remove_str(_renderer, 1))
throw;
}
}
break;
case SDLK_TAB:
CurrentActiveTextInput = next(CurrentActiveTextInput);
break;
case SDLK_RETURN:
case SDLK_RETURN2:
case SDLK_KP_ENTER:
running = false;
res = INPUT_BUTTON_ACCEPT;
break;
case SDLK_ESCAPE:
running = false;
res = INPUT_BUTTON_CANCEL;
break;
case SDLK_V:
if (pressed.size() == 2)
{
if ((pressed[0] == SDLK_LCTRL) || (pressed[0] == SDLK_RCTRL))
{
auto cur = get(CurrentActiveTextInput);
if (cur)
{
auto text = SDL_GetClipboardText();
cur->set_str(_renderer, text);
}
}
}
break;
default:
break;
}
}
break;
case SDL_EVENT_KEY_DOWN:
pressed.push_back(event.key.key);
break;
case SDL_EVENT_TEXT_INPUT:
{
auto cur = get(CurrentActiveTextInput);
if (cur)
{
if (!cur->append_str(_renderer, event.text.text))
throw;
}
}
break;
case SDL_EVENT_MOUSE_MOTION:
{
auto TextInputIndex = get_index(event.button);
for (auto& cur : _list)
{
if (!cur.set_mouseover(_renderer, false))
throw;
}
if (TextInputIndex >= 0)
{
auto& cur = _list[static_cast<size_t>(TextInputIndex)];
if (!cur.set_mouseover(_renderer, true))
throw;
}
_buttons.set_mouseover(event.button.x, event.button.y);
}
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
{
auto val = get_index(event.button);
if (valid(val))
CurrentActiveTextInput = val;
auto button = _buttons.get_selected(event.button);
if (button)
{
running = false;
if (button->id() == INPUT_BUTTON_CANCEL)
res = INPUT_BUTTON_CANCEL;
else
res = INPUT_BUTTON_ACCEPT;
}
}
break;
case SDL_EVENT_QUIT:
res = INPUT_BUTTON_CANCEL;
running = false;
break;
default:
break;
}
if (LastActiveTextInput != CurrentActiveTextInput)
{
if (CurrentActiveTextInput < 0)
SDL_StopTextInput(_window);
else
SDL_StartTextInput(_window);
LastActiveTextInput = CurrentActiveTextInput;
}
for (auto& cur : _list)
{
if (!cur.set_highlight(_renderer, false))
throw;
}
auto cur = get(CurrentActiveTextInput);
if (cur)
{
if (!cur->set_highlight(_renderer, true))
throw;
}
SDL_RenderPresent(_renderer);
}
for (auto& cur : _list)
result.push_back(cur.value());
}
catch (...)
{
}
return res;
}