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, ssize_t selected)
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 auto widget =
54 std::make_shared<SdlInputWidgetPair>(_renderer, labels.at(x), initial.at(x),
55 flags.at(x), x, widget_width, widget_heigth);
56 m_list.emplace_back(widget);
57 }
58
59 std::ignore = _buttons.populate(
60 _renderer, buttonlabels, buttonids, total_width, static_cast<Sint32>(input_height),
61 static_cast<Sint32>(widget_width), static_cast<Sint32>(widget_heigth));
62 _buttons.set_highlight(0);
63 m_currentActiveTextInput = selected;
64 }
65}
66
67ssize_t SdlInputWidgetPairList::next(ssize_t current)
68{
69 size_t iteration = 0;
70 auto val = static_cast<size_t>(current);
71
72 do
73 {
74 if (iteration >= m_list.size())
75 return -1;
76
77 if (iteration == 0)
78 {
79 if (current < 0)
80 val = 0;
81 else
82 val++;
83 }
84 else
85 val++;
86 iteration++;
87 val %= m_list.size();
88 } while (!valid(static_cast<ssize_t>(val)));
89 return static_cast<ssize_t>(val);
90}
91
92bool SdlInputWidgetPairList::valid(ssize_t current) const
93{
94 if (current < 0)
95 return false;
96 auto s = static_cast<size_t>(current);
97 if (s >= m_list.size())
98 return false;
99 return !m_list.at(s)->readonly();
100}
101
102std::shared_ptr<SdlInputWidgetPair> SdlInputWidgetPairList::get(ssize_t index)
103{
104 if (index < 0)
105 return nullptr;
106 auto s = static_cast<size_t>(index);
107 if (s >= m_list.size())
108 return nullptr;
109 return m_list.at(s);
110}
111
112SdlInputWidgetPairList::~SdlInputWidgetPairList()
113{
114 m_list.clear();
115 _buttons.clear();
116}
117
118bool SdlInputWidgetPairList::updateInternal()
119{
120 for (auto& btn : m_list)
121 {
122 if (!btn->update())
123 return false;
124 if (!btn->update())
125 return false;
126 }
127
128 return true;
129}
130
131ssize_t SdlInputWidgetPairList::get_index(const SDL_MouseButtonEvent& button)
132{
133 const auto x = button.x;
134 const auto y = button.y;
135 for (size_t i = 0; i < m_list.size(); i++)
136 {
137 auto& cur = m_list.at(i);
138 auto r = cur->input_rect();
139
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);
142 }
143 return -1;
144}
145
146int SdlInputWidgetPairList::run(std::vector<std::string>& result)
147{
148 int res = -1;
149 ssize_t LastActiveTextInput = -1;
150 m_currentActiveTextInput = next(m_currentActiveTextInput);
151
152 if (!_window || !_renderer)
153 return -2;
154
155 if (!SDL_StartTextInput(_window.get()))
156 return -3;
157
158 try
159 {
160 bool running = true;
161 while (running)
162 {
163 if (!update())
164 throw;
165
166 SDL_Event event = {};
167 if (!SDL_WaitEvent(&event))
168 throw;
169 do
170 {
171 switch (event.type)
172 {
173 case SDL_EVENT_KEY_UP:
174 {
175 switch (event.key.key)
176 {
177 case SDLK_BACKSPACE:
178 {
179 auto cur = get(m_currentActiveTextInput);
180 if (cur)
181 {
182 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
183 {
184 if (!cur->set_str(""))
185 throw;
186 }
187 else
188 {
189 if (!cur->remove_str(1))
190 throw;
191 }
192 }
193 }
194 break;
195 case SDLK_TAB:
196 m_currentActiveTextInput = next(m_currentActiveTextInput);
197 break;
198 case SDLK_RETURN:
199 case SDLK_RETURN2:
200 case SDLK_KP_ENTER:
201 running = false;
202 res = INPUT_BUTTON_ACCEPT;
203 break;
204 case SDLK_ESCAPE:
205 running = false;
206 res = INPUT_BUTTON_CANCEL;
207 break;
208 case SDLK_V:
209 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
210 {
211 auto cur = get(m_currentActiveTextInput);
212 if (cur)
213 {
214 auto text = SDL_GetClipboardText();
215 if (!cur->set_str(text))
216 throw;
217 }
218 }
219 break;
220 default:
221 break;
222 }
223 }
224 break;
225 case SDL_EVENT_TEXT_INPUT:
226 {
227 auto cur = get(m_currentActiveTextInput);
228 if (cur)
229 {
230 if (!cur->append_str(event.text.text))
231 throw;
232 }
233 }
234 break;
235 case SDL_EVENT_MOUSE_MOTION:
236 {
237 auto TextInputIndex = get_index(event.button);
238 for (auto& cur : m_list)
239 {
240 cur->set_mouseover(false);
241 }
242 if (TextInputIndex >= 0)
243 {
244 auto& cur = m_list.at(static_cast<size_t>(TextInputIndex));
245 cur->set_mouseover(true);
246 }
247
248 _buttons.set_mouseover(event.button.x, event.button.y);
249 }
250 break;
251 case SDL_EVENT_MOUSE_BUTTON_DOWN:
252 {
253 auto val = get_index(event.button);
254 if (valid(val))
255 m_currentActiveTextInput = val;
256
257 auto button = _buttons.get_selected(event.button);
258 if (button)
259 {
260 running = false;
261 if (button->id() == INPUT_BUTTON_CANCEL)
262 res = INPUT_BUTTON_CANCEL;
263 else
264 res = INPUT_BUTTON_ACCEPT;
265 }
266 }
267 break;
268 case SDL_EVENT_QUIT:
269 res = INPUT_BUTTON_CANCEL;
270 running = false;
271 break;
272 default:
273 break;
274 }
275 } while (SDL_PollEvent(&event));
276
277 if (LastActiveTextInput != m_currentActiveTextInput)
278 {
279 LastActiveTextInput = m_currentActiveTextInput;
280 }
281
282 for (auto& cur : m_list)
283 {
284 if (!cur->set_highlight(false))
285 throw;
286 }
287 auto cur = get(m_currentActiveTextInput);
288 if (cur)
289 {
290 if (!cur->set_highlight(true))
291 throw;
292 }
293
294 auto rc = SDL_RenderPresent(_renderer.get());
295 if (!rc)
296 {
297 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] SDL_RenderPresent failed with %s",
298 __func__, SDL_GetError());
299 }
300 }
301
302 for (auto& cur : m_list)
303 result.push_back(cur->value());
304 }
305 catch (...)
306 {
307 res = -2;
308 }
309 if (!SDL_StopTextInput(_window.get()))
310 return -4;
311
312 return res;
313}