24#include <winpr/cast.h>
26#include "../sdl_utils.hpp"
27#include "sdl_widget_list.hpp"
28#include "sdl_input_widget_pair_list.hpp"
30static const Uint32 vpadding = 5;
32SdlInputWidgetPairList::SdlInputWidgetPairList(
const std::string& title,
33 const std::vector<std::string>& labels,
34 const std::vector<std::string>& initial,
35 const std::vector<Uint32>& flags, ssize_t selected)
37 assert(labels.size() == initial.size());
38 assert(labels.size() == flags.size());
39 const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
40 const std::vector<std::string> buttonlabels = {
"accept",
"cancel" };
42 const size_t widget_width = 300;
43 const size_t widget_height = 50;
45 const size_t total_width = widget_width + widget_width;
46 const size_t input_height = labels.size() * (widget_height + vpadding) + vpadding;
47 const size_t total_height = input_height + widget_height;
48 assert(total_width <= INT32_MAX);
49 assert(total_height <= INT32_MAX);
51 if (reset(title, total_width, total_height))
53 for (
size_t x = 0; x < labels.size(); x++)
56 std::make_shared<SdlInputWidgetPair>(_renderer, labels.at(x), initial.at(x),
57 flags.at(x), x, widget_width, widget_height);
58 m_list.emplace_back(widget);
61 std::ignore = _buttons.populate(
62 _renderer, buttonlabels, buttonids, total_width,
static_cast<Sint32
>(input_height),
63 static_cast<Sint32
>(widget_width),
static_cast<Sint32
>(widget_height));
64 _buttons.set_highlight(0);
65 m_currentActiveTextInput = selected;
69ssize_t SdlInputWidgetPairList::next(ssize_t current)
72 auto val =
static_cast<size_t>(current);
76 if (iteration >= m_list.size())
90 }
while (!valid(
static_cast<ssize_t
>(val)));
91 return static_cast<ssize_t
>(val);
94bool SdlInputWidgetPairList::valid(ssize_t current)
const
98 auto s =
static_cast<size_t>(current);
99 if (s >= m_list.size())
101 return !m_list.at(s)->readonly();
104std::shared_ptr<SdlInputWidgetPair> SdlInputWidgetPairList::get(ssize_t index)
108 auto s =
static_cast<size_t>(index);
109 if (s >= m_list.size())
114SdlInputWidgetPairList::~SdlInputWidgetPairList()
120bool SdlInputWidgetPairList::updateInternal()
122 for (
auto& btn : m_list)
131ssize_t SdlInputWidgetPairList::get_index(
const SDL_MouseButtonEvent& button)
133 const auto x = button.x;
134 const auto y = button.y;
135 for (
size_t i = 0; i < m_list.size(); i++)
137 auto& cur = m_list.at(i);
138 auto r = cur->input_rect();
140 if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
141 return WINPR_ASSERTING_INT_CAST(ssize_t, i);
146int SdlInputWidgetPairList::run(std::vector<std::string>& result)
149 ssize_t LastActiveTextInput = -1;
150 m_currentActiveTextInput = next(m_currentActiveTextInput);
152 if (!_window || !_renderer)
155 if (!SDL_StartTextInput(_window.get()))
158 std::optional<SDL_Event> forward;
165 throw std::exception();
167 SDL_Event
event = {};
168 if (!SDL_WaitEventTimeout(&event, 30))
174 case SDL_EVENT_KEY_UP:
176 switch (event.key.key)
180 auto cur = get(m_currentActiveTextInput);
183 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
185 if (!cur->set_str(
""))
186 throw std::exception();
190 if (!cur->remove_str(1))
191 throw std::exception();
197 m_currentActiveTextInput = next(m_currentActiveTextInput);
203 res = INPUT_BUTTON_ACCEPT;
207 res = INPUT_BUTTON_CANCEL;
210 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
212 auto cur = get(m_currentActiveTextInput);
215 auto text = SDL_GetClipboardText();
216 if (!cur->set_str(text))
217 throw std::exception();
226 case SDL_EVENT_TEXT_INPUT:
228 auto cur = get(m_currentActiveTextInput);
231 if (!cur->append_str(event.text.text))
232 throw std::exception();
236 case SDL_EVENT_MOUSE_MOTION:
238 auto TextInputIndex = get_index(event.button);
239 for (
auto& cur : m_list)
241 cur->set_mouseover(
false);
243 if (TextInputIndex >= 0)
245 auto& cur = m_list.at(
static_cast<size_t>(TextInputIndex));
246 cur->set_mouseover(
true);
249 _buttons.set_mouseover(event.button.x, event.button.y);
252 case SDL_EVENT_MOUSE_BUTTON_DOWN:
254 auto val = get_index(event.button);
256 m_currentActiveTextInput = val;
258 auto button = _buttons.get_selected(event.button);
262 if (button->id() == INPUT_BUTTON_CANCEL)
263 res = INPUT_BUTTON_CANCEL;
265 res = INPUT_BUTTON_ACCEPT;
269 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
273 if (event.window.windowID != SDL_GetWindowID(_window.get()))
275 res = INPUT_BUTTON_CANCEL;
278 case SDL_EVENT_WINDOW_OCCLUDED:
279 case SDL_EVENT_WINDOW_MINIMIZED:
280 case SDL_EVENT_WINDOW_DESTROYED:
284 if (event.window.windowID != SDL_GetWindowID(_window.get()))
286 res = INPUT_BUTTON_CANCEL;
289 case SDL_EVENT_TERMINATING:
291 res = INPUT_BUTTON_CANCEL;
297 }
while (running && SDL_PollEvent(&event));
299 if (LastActiveTextInput != m_currentActiveTextInput)
301 LastActiveTextInput = m_currentActiveTextInput;
304 for (
auto& cur : m_list)
306 if (!cur->set_highlight(
false))
307 throw std::exception();
309 auto cur = get(m_currentActiveTextInput);
312 if (!cur->set_highlight(
true))
313 throw std::exception();
317 for (
auto& cur : m_list)
318 result.push_back(cur->value());
328 SDL_FlushEvents(SDL_EVENT_KEY_DOWN, SDL_EVENT_MOUSE_REMOVED);
329 SDL_FlushEvents(SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_CANCELED);
330 SDL_FlushEvents(SDL_EVENT_PEN_PROXIMITY_IN, SDL_EVENT_PEN_AXIS);
332 std::ignore = SDL_PushEvent(&*forward);
334 if (!SDL_StopTextInput(_window.get()))
340void SdlInputWidgetPairList::parent(SDL_Window* parent)
344 SDL_SetWindowParent(_window.get(), parent);
345 SDL_SetWindowModal(_window.get(),
true);