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