summaryrefslogtreecommitdiffstats
path: root/client/SDL/dialogs/sdl_input_widgets.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/SDL/dialogs/sdl_input_widgets.cpp')
-rw-r--r--client/SDL/dialogs/sdl_input_widgets.cpp299
1 files changed, 299 insertions, 0 deletions
diff --git a/client/SDL/dialogs/sdl_input_widgets.cpp b/client/SDL/dialogs/sdl_input_widgets.cpp
new file mode 100644
index 0000000..5846308
--- /dev/null
+++ b/client/SDL/dialogs/sdl_input_widgets.cpp
@@ -0,0 +1,299 @@
+#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;
+ _window = SDL_CreateWindow(
+ title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, total_width, total_height,
+ SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS);
+ if (_window == nullptr)
+ {
+ widget_log_error(-1, "SDL_CreateWindow");
+ }
+ else
+ {
+
+ _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
+ if (_renderer == nullptr)
+ {
+ widget_log_error(-1, "SDL_CreateRenderer");
+ }
+ 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_KEYUP:
+ {
+ auto it = std::remove(pressed.begin(), pressed.end(), event.key.keysym.sym);
+ pressed.erase(it, pressed.end());
+ }
+ break;
+ case SDL_KEYDOWN:
+ pressed.push_back(event.key.keysym.sym);
+ switch (event.key.keysym.sym)
+ {
+ 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_TEXTINPUT:
+ {
+ auto cur = get(CurrentActiveTextInput);
+ if (cur)
+ {
+ if (!cur->append_str(_renderer, event.text.text))
+ throw;
+ }
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ {
+ 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_MOUSEBUTTONDOWN:
+ {
+ 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_QUIT:
+ res = INPUT_BUTTON_CANCEL;
+ running = false;
+ break;
+ default:
+ break;
+ }
+
+ if (LastActiveTextInput != CurrentActiveTextInput)
+ {
+ if (CurrentActiveTextInput < 0)
+ SDL_StopTextInput();
+ else
+ SDL_StartTextInput();
+ 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;
+}