FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
SDL3/dialogs/sdl_selectlist.cpp
1#include <cassert>
2#include <winpr/cast.h>
3#include "sdl_selectlist.hpp"
4#include "../sdl_utils.hpp"
5
6static const Uint32 vpadding = 5;
7
8SdlSelectList::SdlSelectList(const std::string& title, const std::vector<std::string>& labels)
9{
10 const size_t widget_height = 50;
11 const size_t widget_width = 600;
12
13 const size_t total_height = labels.size() * (widget_height + vpadding) + vpadding;
14 const size_t height = total_height + widget_height;
15 if (reset(title, widget_width, height))
16 {
17 SDL_FRect rect = { 0, 0, widget_width, widget_height };
18 for (auto& label : labels)
19 {
20 _list.emplace_back(_renderer, label, rect);
21 rect.y += widget_height + vpadding;
22 }
23
24 const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
25 const std::vector<std::string> buttonlabels = { "accept", "cancel" };
26 _buttons.populate(_renderer, buttonlabels, buttonids, widget_width,
27 static_cast<Sint32>(total_height), static_cast<Sint32>(widget_width / 2),
28 static_cast<Sint32>(widget_height));
29 _buttons.set_highlight(0);
30 }
31}
32
33SdlSelectList::~SdlSelectList()
34{
35 _list.clear();
36 _buttons.clear();
37}
38
39int SdlSelectList::run()
40{
41 int res = -2;
42 ssize_t CurrentActiveTextInput = 0;
43 bool running = true;
44
45 if (!_window || !_renderer)
46 return -2;
47 try
48 {
49 while (running)
50 {
51 if (!SdlWidget::clear_window(_renderer))
52 throw;
53
54 if (!update_text())
55 throw;
56
57 if (!_buttons.update(_renderer))
58 throw;
59
60 SDL_Event event = {};
61 if (!SDL_WaitEvent(&event))
62 throw;
63 do
64 {
65 switch (event.type)
66 {
67 case SDL_EVENT_KEY_DOWN:
68 switch (event.key.key)
69 {
70 case SDLK_UP:
71 case SDLK_BACKSPACE:
72 if (CurrentActiveTextInput > 0)
73 CurrentActiveTextInput--;
74 else if (_list.empty())
75 CurrentActiveTextInput = 0;
76 else
77 {
78 auto s = _list.size();
79 CurrentActiveTextInput =
80 WINPR_ASSERTING_INT_CAST(ssize_t, s) - 1;
81 }
82 break;
83 case SDLK_DOWN:
84 case SDLK_TAB:
85 if ((CurrentActiveTextInput < 0) || _list.empty())
86 CurrentActiveTextInput = 0;
87 else
88 {
89 auto s = _list.size();
90 CurrentActiveTextInput++;
91 if (s > 0)
92 {
93 CurrentActiveTextInput =
94 CurrentActiveTextInput %
95 WINPR_ASSERTING_INT_CAST(ssize_t, s);
96 }
97 }
98 break;
99 case SDLK_RETURN:
100 case SDLK_RETURN2:
101 case SDLK_KP_ENTER:
102 running = false;
103 res = static_cast<int>(CurrentActiveTextInput);
104 break;
105 case SDLK_ESCAPE:
106 running = false;
107 res = INPUT_BUTTON_CANCEL;
108 break;
109 default:
110 break;
111 }
112 break;
113 case SDL_EVENT_MOUSE_MOTION:
114 {
115 auto TextInputIndex = get_index(event.button);
116 reset_mouseover();
117 if (TextInputIndex >= 0)
118 {
119 auto& cur = _list[WINPR_ASSERTING_INT_CAST(size_t, TextInputIndex)];
120 if (!cur.set_mouseover(_renderer, true))
121 throw;
122 }
123
124 _buttons.set_mouseover(event.button.x, event.button.y);
125 }
126 break;
127 case SDL_EVENT_MOUSE_BUTTON_DOWN:
128 {
129 auto button = _buttons.get_selected(event.button);
130 if (button)
131 {
132 running = false;
133 if (button->id() == INPUT_BUTTON_CANCEL)
134 res = INPUT_BUTTON_CANCEL;
135 else
136 res = static_cast<int>(CurrentActiveTextInput);
137 }
138 else
139 {
140 CurrentActiveTextInput = get_index(event.button);
141 }
142 }
143 break;
144 case SDL_EVENT_QUIT:
145 res = INPUT_BUTTON_CANCEL;
146 running = false;
147 break;
148 default:
149 break;
150 }
151 } while (SDL_PollEvent(&event));
152 reset_highlight();
153 if (CurrentActiveTextInput >= 0)
154 {
155 auto& cur = _list[WINPR_ASSERTING_INT_CAST(size_t, CurrentActiveTextInput)];
156 if (!cur.set_highlight(_renderer, true))
157 throw;
158 }
159
160 auto rc = SDL_RenderPresent(_renderer.get());
161 if (!rc)
162 {
163 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "SDL_RenderPresent failed with %s",
164 SDL_GetError());
165 }
166 }
167 }
168 catch (...)
169 {
170 return -1;
171 }
172 return res;
173}
174
175ssize_t SdlSelectList::get_index(const SDL_MouseButtonEvent& button)
176{
177 const auto x = button.x;
178 const auto y = button.y;
179 for (size_t i = 0; i < _list.size(); i++)
180 {
181 auto& cur = _list[i];
182 auto r = cur.rect();
183
184 if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
185 return WINPR_ASSERTING_INT_CAST(ssize_t, i);
186 }
187 return -1;
188}
189
190bool SdlSelectList::update_text()
191{
192 for (auto& cur : _list)
193 {
194 if (!cur.update_text(_renderer))
195 return false;
196 }
197
198 return true;
199}
200
201void SdlSelectList::reset_mouseover()
202{
203 for (auto& cur : _list)
204 {
205 cur.set_mouseover(_renderer, false);
206 }
207}
208
209void SdlSelectList::reset_highlight()
210{
211 for (auto& cur : _list)
212 {
213 cur.set_highlight(_renderer, false);
214 }
215}