FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
SDL3/dialogs/sdl_input_widgets.cpp
1
20#include <cassert>
21#include <algorithm>
22
23#include <winpr/cast.h>
24
25#include "sdl_widget_list.hpp"
26#include "sdl_input_widgets.hpp"
27
28static const Uint32 vpadding = 5;
29
30SdlInputWidgetList::SdlInputWidgetList(const std::string& title,
31 const std::vector<std::string>& labels,
32 const std::vector<std::string>& initial,
33 const std::vector<Uint32>& flags)
34{
35 assert(labels.size() == initial.size());
36 assert(labels.size() == flags.size());
37 const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
38 const std::vector<std::string> buttonlabels = { "accept", "cancel" };
39
40 const size_t widget_width = 300;
41 const size_t widget_heigth = 50;
42
43 const size_t total_width = widget_width + widget_width;
44 const size_t input_height = labels.size() * (widget_heigth + vpadding) + vpadding;
45 const size_t total_height = input_height + widget_heigth;
46 assert(total_width <= INT32_MAX);
47 assert(total_height <= INT32_MAX);
48
49 if (reset(title, total_width, total_height))
50 {
51 for (size_t x = 0; x < labels.size(); x++)
52 {
53 std::shared_ptr<SdlInputWidget> widget(new SdlInputWidget(
54 _renderer, labels[x], initial[x], flags[x], x, widget_width, widget_heigth));
55 _list.emplace_back(widget);
56 }
57
58 _buttons.populate(_renderer, buttonlabels, buttonids, total_width,
59 static_cast<Sint32>(input_height), static_cast<Sint32>(widget_width),
60 static_cast<Sint32>(widget_heigth));
61 _buttons.set_highlight(0);
62 }
63}
64
65ssize_t SdlInputWidgetList::next(ssize_t current)
66{
67 size_t iteration = 0;
68 auto val = static_cast<size_t>(current);
69
70 do
71 {
72 if (iteration >= _list.size())
73 return -1;
74
75 if (iteration == 0)
76 {
77 if (current < 0)
78 val = 0;
79 else
80 val++;
81 }
82 else
83 val++;
84 iteration++;
85 val %= _list.size();
86 } while (!valid(static_cast<ssize_t>(val)));
87 return static_cast<ssize_t>(val);
88}
89
90bool SdlInputWidgetList::valid(ssize_t current) const
91{
92 if (current < 0)
93 return false;
94 auto s = static_cast<size_t>(current);
95 if (s >= _list.size())
96 return false;
97 return !_list[s]->readonly();
98}
99
100std::shared_ptr<SdlInputWidget> SdlInputWidgetList::get(ssize_t index)
101{
102 if (index < 0)
103 return nullptr;
104 auto s = static_cast<size_t>(index);
105 if (s >= _list.size())
106 return nullptr;
107 return _list[s];
108}
109
110SdlInputWidgetList::~SdlInputWidgetList()
111{
112 _list.clear();
113 _buttons.clear();
114}
115
116bool SdlInputWidgetList::update(std::shared_ptr<SDL_Renderer>& renderer)
117{
118 for (auto& btn : _list)
119 {
120 if (!btn->update_label(renderer))
121 return false;
122 if (!btn->update_input(renderer))
123 return false;
124 }
125
126 return _buttons.update(renderer);
127}
128
129ssize_t SdlInputWidgetList::get_index(const SDL_MouseButtonEvent& button)
130{
131 const auto x = button.x;
132 const auto y = button.y;
133 for (size_t i = 0; i < _list.size(); i++)
134 {
135 auto& cur = _list[i];
136 auto r = cur->input_rect();
137
138 if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
139 return WINPR_ASSERTING_INT_CAST(ssize_t, i);
140 }
141 return -1;
142}
143
144int SdlInputWidgetList::run(std::vector<std::string>& result)
145{
146 int res = -1;
147 ssize_t LastActiveTextInput = -1;
148 ssize_t CurrentActiveTextInput = next(-1);
149
150 if (!_window || !_renderer)
151 return -2;
152
153 if (!SDL_StartTextInput(_window.get()))
154 return -3;
155
156 try
157 {
158 bool running = true;
159 while (running)
160 {
161 if (!SdlWidget::clear_window(_renderer))
162 throw;
163
164 if (!update(_renderer))
165 throw;
166
167 SDL_Event event = {};
168 if (!SDL_WaitEvent(&event))
169 throw;
170 do
171 {
172 switch (event.type)
173 {
174 case SDL_EVENT_KEY_UP:
175 {
176 switch (event.key.key)
177 {
178 case SDLK_BACKSPACE:
179 {
180 auto cur = get(CurrentActiveTextInput);
181 if (cur)
182 {
183 if (!cur->remove_str(_renderer, 1))
184 throw;
185 }
186 }
187 break;
188 case SDLK_TAB:
189 CurrentActiveTextInput = next(CurrentActiveTextInput);
190 break;
191 case SDLK_RETURN:
192 case SDLK_RETURN2:
193 case SDLK_KP_ENTER:
194 running = false;
195 res = INPUT_BUTTON_ACCEPT;
196 break;
197 case SDLK_ESCAPE:
198 running = false;
199 res = INPUT_BUTTON_CANCEL;
200 break;
201 case SDLK_V:
202 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
203 {
204 auto cur = get(CurrentActiveTextInput);
205 if (cur)
206 {
207 auto text = SDL_GetClipboardText();
208 cur->set_str(_renderer, text);
209 }
210 }
211 break;
212 default:
213 break;
214 }
215 }
216 break;
217 case SDL_EVENT_TEXT_INPUT:
218 {
219 auto cur = get(CurrentActiveTextInput);
220 if (cur)
221 {
222 if (!cur->append_str(_renderer, event.text.text))
223 throw;
224 }
225 }
226 break;
227 case SDL_EVENT_MOUSE_MOTION:
228 {
229 auto TextInputIndex = get_index(event.button);
230 for (auto& cur : _list)
231 {
232 if (!cur->set_mouseover(_renderer, false))
233 throw;
234 }
235 if (TextInputIndex >= 0)
236 {
237 auto& cur = _list[static_cast<size_t>(TextInputIndex)];
238 if (!cur->set_mouseover(_renderer, true))
239 throw;
240 }
241
242 _buttons.set_mouseover(event.button.x, event.button.y);
243 }
244 break;
245 case SDL_EVENT_MOUSE_BUTTON_DOWN:
246 {
247 auto val = get_index(event.button);
248 if (valid(val))
249 CurrentActiveTextInput = val;
250
251 auto button = _buttons.get_selected(event.button);
252 if (button)
253 {
254 running = false;
255 if (button->id() == INPUT_BUTTON_CANCEL)
256 res = INPUT_BUTTON_CANCEL;
257 else
258 res = INPUT_BUTTON_ACCEPT;
259 }
260 }
261 break;
262 case SDL_EVENT_QUIT:
263 res = INPUT_BUTTON_CANCEL;
264 running = false;
265 break;
266 default:
267 break;
268 }
269 } while (SDL_PollEvent(&event));
270
271 if (LastActiveTextInput != CurrentActiveTextInput)
272 {
273 LastActiveTextInput = CurrentActiveTextInput;
274 }
275
276 for (auto& cur : _list)
277 {
278 if (!cur->set_highlight(_renderer, false))
279 throw;
280 }
281 auto cur = get(CurrentActiveTextInput);
282 if (cur)
283 {
284 if (!cur->set_highlight(_renderer, true))
285 throw;
286 }
287
288 auto rc = SDL_RenderPresent(_renderer.get());
289 if (!rc)
290 {
291 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "SDL_RenderPresent failed with %s",
292 SDL_GetError());
293 }
294 }
295
296 for (auto& cur : _list)
297 result.push_back(cur->value());
298 }
299 catch (...)
300 {
301 res = -2;
302 }
303 if (!SDL_StopTextInput(_window.get()))
304 return -4;
305
306 return res;
307}