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 std::shared_ptr<SdlInputWidgetPair> widget(new SdlInputWidgetPair(
54 _renderer, labels[x], initial[x], flags[x], x, widget_width, widget_heigth));
55 m_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 m_currentActiveTextInput = selected;
63 }
64}
65
66ssize_t SdlInputWidgetPairList::next(ssize_t current)
67{
68 size_t iteration = 0;
69 auto val = static_cast<size_t>(current);
70
71 do
72 {
73 if (iteration >= m_list.size())
74 return -1;
75
76 if (iteration == 0)
77 {
78 if (current < 0)
79 val = 0;
80 else
81 val++;
82 }
83 else
84 val++;
85 iteration++;
86 val %= m_list.size();
87 } while (!valid(static_cast<ssize_t>(val)));
88 return static_cast<ssize_t>(val);
89}
90
91bool SdlInputWidgetPairList::valid(ssize_t current) const
92{
93 if (current < 0)
94 return false;
95 auto s = static_cast<size_t>(current);
96 if (s >= m_list.size())
97 return false;
98 return !m_list[s]->readonly();
99}
100
101std::shared_ptr<SdlInputWidgetPair> SdlInputWidgetPairList::get(ssize_t index)
102{
103 if (index < 0)
104 return nullptr;
105 auto s = static_cast<size_t>(index);
106 if (s >= m_list.size())
107 return nullptr;
108 return m_list[s];
109}
110
111SdlInputWidgetPairList::~SdlInputWidgetPairList()
112{
113 m_list.clear();
114 _buttons.clear();
115}
116
117bool SdlInputWidgetPairList::updateInternal()
118{
119 for (auto& btn : m_list)
120 {
121 if (!btn->update())
122 return false;
123 if (!btn->update())
124 return false;
125 }
126
127 return true;
128}
129
130ssize_t SdlInputWidgetPairList::get_index(const SDL_MouseButtonEvent& button)
131{
132 const auto x = button.x;
133 const auto y = button.y;
134 for (size_t i = 0; i < m_list.size(); i++)
135 {
136 auto& cur = m_list[i];
137 auto r = cur->input_rect();
138
139 if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
140 return WINPR_ASSERTING_INT_CAST(ssize_t, i);
141 }
142 return -1;
143}
144
145int SdlInputWidgetPairList::run(std::vector<std::string>& result)
146{
147 int res = -1;
148 ssize_t LastActiveTextInput = -1;
149 m_currentActiveTextInput = next(m_currentActiveTextInput);
150
151 if (!_window || !_renderer)
152 return -2;
153
154 if (!SDL_StartTextInput(_window.get()))
155 return -3;
156
157 try
158 {
159 bool running = true;
160 while (running)
161 {
162 if (!update())
163 throw;
164
165 SDL_Event event = {};
166 if (!SDL_WaitEvent(&event))
167 throw;
168 do
169 {
170 switch (event.type)
171 {
172 case SDL_EVENT_KEY_UP:
173 {
174 switch (event.key.key)
175 {
176 case SDLK_BACKSPACE:
177 {
178 auto cur = get(m_currentActiveTextInput);
179 if (cur)
180 {
181 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
182 {
183 if (!cur->set_str(""))
184 throw;
185 }
186 else
187 {
188 if (!cur->remove_str(1))
189 throw;
190 }
191 }
192 }
193 break;
194 case SDLK_TAB:
195 m_currentActiveTextInput = next(m_currentActiveTextInput);
196 break;
197 case SDLK_RETURN:
198 case SDLK_RETURN2:
199 case SDLK_KP_ENTER:
200 running = false;
201 res = INPUT_BUTTON_ACCEPT;
202 break;
203 case SDLK_ESCAPE:
204 running = false;
205 res = INPUT_BUTTON_CANCEL;
206 break;
207 case SDLK_V:
208 if ((event.key.mod & SDL_KMOD_CTRL) != 0)
209 {
210 auto cur = get(m_currentActiveTextInput);
211 if (cur)
212 {
213 auto text = SDL_GetClipboardText();
214 cur->set_str(text);
215 }
216 }
217 break;
218 default:
219 break;
220 }
221 }
222 break;
223 case SDL_EVENT_TEXT_INPUT:
224 {
225 auto cur = get(m_currentActiveTextInput);
226 if (cur)
227 {
228 if (!cur->append_str(event.text.text))
229 throw;
230 }
231 }
232 break;
233 case SDL_EVENT_MOUSE_MOTION:
234 {
235 auto TextInputIndex = get_index(event.button);
236 for (auto& cur : m_list)
237 {
238 if (!cur->set_mouseover(false))
239 throw;
240 }
241 if (TextInputIndex >= 0)
242 {
243 auto& cur = m_list[static_cast<size_t>(TextInputIndex)];
244 if (!cur->set_mouseover(true))
245 throw;
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}