FreeRDP
Loading...
Searching...
No Matches
sdl_input_widget_pair_list.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_widget_pair_list.hpp"
27
28static const Uint32 vpadding = 5;
29
30SdlInputWidgetPairList::SdlInputWidgetPairList(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<SdlInputWidgetPair> widget(new SdlInputWidgetPair(
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 SdlInputWidgetPairList::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 SdlInputWidgetPairList::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<SdlInputWidgetPair> SdlInputWidgetPairList::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
110SdlInputWidgetPairList::~SdlInputWidgetPairList()
111{
112 _list.clear();
113 _buttons.clear();
114}
115
116bool SdlInputWidgetPairList::updateInternal()
117{
118 for (auto& btn : _list)
119 {
120 if (!btn->update())
121 return false;
122 if (!btn->update())
123 return false;
124 }
125
126 return true;
127}
128
129ssize_t SdlInputWidgetPairList::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 SdlInputWidgetPairList::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 (!update())
162 throw;
163
164 SDL_Event event = {};
165 if (!SDL_WaitEvent(&event))
166 throw;
167 do
168 {
169 switch (event.type)
170 {
171 case SDL_EVENT_KEY_UP:
172 {
173 switch (event.key.key)
174 {
175 case SDLK_BACKSPACE:
176 {
177 auto cur = get(CurrentActiveTextInput);
178 if (cur)
179 {
180 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
181 {
182 if (!cur->set_str(""))
183 throw;
184 }
185 else
186 {
187 if (!cur->remove_str(1))
188 throw;
189 }
190 }
191 }
192 break;
193 case SDLK_TAB:
194 CurrentActiveTextInput = next(CurrentActiveTextInput);
195 break;
196 case SDLK_RETURN:
197 case SDLK_RETURN2:
198 case SDLK_KP_ENTER:
199 running = false;
200 res = INPUT_BUTTON_ACCEPT;
201 break;
202 case SDLK_ESCAPE:
203 running = false;
204 res = INPUT_BUTTON_CANCEL;
205 break;
206 case SDLK_V:
207 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
208 {
209 auto cur = get(CurrentActiveTextInput);
210 if (cur)
211 {
212 auto text = SDL_GetClipboardText();
213 cur->set_str(text);
214 }
215 }
216 break;
217 default:
218 break;
219 }
220 }
221 break;
222 case SDL_EVENT_TEXT_INPUT:
223 {
224 auto cur = get(CurrentActiveTextInput);
225 if (cur)
226 {
227 if (!cur->append_str(event.text.text))
228 throw;
229 }
230 }
231 break;
232 case SDL_EVENT_MOUSE_MOTION:
233 {
234 auto TextInputIndex = get_index(event.button);
235 for (auto& cur : _list)
236 {
237 if (!cur->set_mouseover(false))
238 throw;
239 }
240 if (TextInputIndex >= 0)
241 {
242 auto& cur = _list[static_cast<size_t>(TextInputIndex)];
243 if (!cur->set_mouseover(true))
244 throw;
245 }
246
247 _buttons.set_mouseover(event.button.x, event.button.y);
248 }
249 break;
250 case SDL_EVENT_MOUSE_BUTTON_DOWN:
251 {
252 auto val = get_index(event.button);
253 if (valid(val))
254 CurrentActiveTextInput = val;
255
256 auto button = _buttons.get_selected(event.button);
257 if (button)
258 {
259 running = false;
260 if (button->id() == INPUT_BUTTON_CANCEL)
261 res = INPUT_BUTTON_CANCEL;
262 else
263 res = INPUT_BUTTON_ACCEPT;
264 }
265 }
266 break;
267 case SDL_EVENT_QUIT:
268 res = INPUT_BUTTON_CANCEL;
269 running = false;
270 break;
271 default:
272 break;
273 }
274 } while (SDL_PollEvent(&event));
275
276 if (LastActiveTextInput != CurrentActiveTextInput)
277 {
278 LastActiveTextInput = CurrentActiveTextInput;
279 }
280
281 for (auto& cur : _list)
282 {
283 if (!cur->set_highlight(false))
284 throw;
285 }
286 auto cur = get(CurrentActiveTextInput);
287 if (cur)
288 {
289 if (!cur->set_highlight(true))
290 throw;
291 }
292
293 auto rc = SDL_RenderPresent(_renderer.get());
294 if (!rc)
295 {
296 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "SDL_RenderPresent failed with %s",
297 SDL_GetError());
298 }
299 }
300
301 for (auto& cur : _list)
302 result.push_back(cur->value());
303 }
304 catch (...)
305 {
306 res = -2;
307 }
308 if (!SDL_StopTextInput(_window.get()))
309 return -4;
310
311 return res;
312}