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