FreeRDP
Loading...
Searching...
No Matches
SDL3/dialogs/sdl_selectlist.cpp
1#include <cassert>
2#include <winpr/cast.h>
3#include "sdl_selectlist.hpp"
4
5static const Uint32 vpadding = 5;
6
7SdlSelectList::SdlSelectList(const std::string& title, const std::vector<std::string>& labels)
8 : _window(nullptr), _renderer(nullptr)
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 static_assert(widget_width <= INT32_MAX);
16 assert(height <= INT32_MAX);
17 auto rc = SDL_CreateWindowAndRenderer(
18 title.c_str(), static_cast<int>(widget_width), static_cast<int>(height),
19 SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS, &_window,
20 &_renderer);
21 if (rc != 0)
22 widget_log_error(rc, "SDL_CreateWindowAndRenderer");
23 else
24 {
25 SDL_FRect rect = { 0, 0, widget_width, widget_height };
26 for (auto& label : labels)
27 {
28 _list.emplace_back(_renderer, label, rect);
29 rect.y += widget_height + vpadding;
30 }
31
32 const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
33 const std::vector<std::string> buttonlabels = { "accept", "cancel" };
34 _buttons.populate(_renderer, buttonlabels, buttonids, widget_width,
35 static_cast<Sint32>(total_height), static_cast<Sint32>(widget_width / 2),
36 static_cast<Sint32>(widget_height));
37 _buttons.set_highlight(0);
38 }
39}
40
41SdlSelectList::~SdlSelectList()
42{
43 _list.clear();
44 _buttons.clear();
45 SDL_DestroyRenderer(_renderer);
46 SDL_DestroyWindow(_window);
47}
48
49int SdlSelectList::run()
50{
51 int res = -2;
52 ssize_t CurrentActiveTextInput = 0;
53 bool running = true;
54
55 if (!_window || !_renderer)
56 return -2;
57 try
58 {
59 while (running)
60 {
61 if (!clear_window(_renderer))
62 throw;
63
64 if (!update_text())
65 throw;
66
67 if (!_buttons.update(_renderer))
68 throw;
69
70 SDL_Event event = {};
71 SDL_WaitEvent(&event);
72 switch (event.type)
73 {
74 case SDL_EVENT_KEY_DOWN:
75 switch (event.key.key)
76 {
77 case SDLK_UP:
78 case SDLK_BACKSPACE:
79 if (CurrentActiveTextInput > 0)
80 CurrentActiveTextInput--;
81 else if (_list.empty())
82 CurrentActiveTextInput = 0;
83 else
84 {
85 auto s = _list.size();
86 CurrentActiveTextInput = WINPR_ASSERTING_INT_CAST(ssize_t, s) - 1;
87 }
88 break;
89 case SDLK_DOWN:
90 case SDLK_TAB:
91 if ((CurrentActiveTextInput < 0) || _list.empty())
92 CurrentActiveTextInput = 0;
93 else
94 {
95 auto s = _list.size();
96 CurrentActiveTextInput++;
97 if (s > 0)
98 {
99 CurrentActiveTextInput = CurrentActiveTextInput %
100 WINPR_ASSERTING_INT_CAST(ssize_t, s);
101 }
102 }
103 break;
104 case SDLK_RETURN:
105 case SDLK_RETURN2:
106 case SDLK_KP_ENTER:
107 running = false;
108 res = static_cast<int>(CurrentActiveTextInput);
109 break;
110 case SDLK_ESCAPE:
111 running = false;
112 res = INPUT_BUTTON_CANCEL;
113 break;
114 default:
115 break;
116 }
117 break;
118 case SDL_EVENT_MOUSE_MOTION:
119 {
120 ssize_t TextInputIndex = get_index(event.button);
121 reset_mouseover();
122 if (TextInputIndex >= 0)
123 {
124 auto& cur = _list[WINPR_ASSERTING_INT_CAST(size_t, TextInputIndex)];
125 if (!cur.set_mouseover(_renderer, true))
126 throw;
127 }
128
129 _buttons.set_mouseover(event.button.x, event.button.y);
130 }
131 break;
132 case SDL_EVENT_MOUSE_BUTTON_DOWN:
133 {
134 auto button = _buttons.get_selected(event.button);
135 if (button)
136 {
137 running = false;
138 if (button->id() == INPUT_BUTTON_CANCEL)
139 res = INPUT_BUTTON_CANCEL;
140 else
141 res = static_cast<int>(CurrentActiveTextInput);
142 }
143 else
144 {
145 CurrentActiveTextInput = get_index(event.button);
146 }
147 }
148 break;
149 case SDL_EVENT_QUIT:
150 res = INPUT_BUTTON_CANCEL;
151 running = false;
152 break;
153 default:
154 break;
155 }
156
157 reset_highlight();
158 if (CurrentActiveTextInput >= 0)
159 {
160 auto& cur = _list[WINPR_ASSERTING_INT_CAST(size_t, CurrentActiveTextInput)];
161 if (!cur.set_highlight(_renderer, true))
162 throw;
163 }
164
165 SDL_RenderPresent(_renderer);
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}