The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
lobby.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Tomasz Sniatowski <kailoran@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #define GETTEXT_DOMAIN "wesnoth-lib"
15 
17 
19 #include "gui/dialogs/message.hpp"
23 #include "gui/dialogs/helper.hpp"
24 
25 #include "gui/core/log.hpp"
26 #include "gui/core/timer.hpp"
27 #include "gui/widgets/button.hpp"
28 #include "gui/widgets/image.hpp"
29 #include "gui/widgets/label.hpp"
30 #ifdef GUI2_EXPERIMENTAL_LISTBOX
31 #include "gui/widgets/list.hpp"
32 #else
33 #include "gui/widgets/listbox.hpp"
34 #endif
36 #include "gui/widgets/minimap.hpp"
37 #include "gui/widgets/chatbox.hpp"
38 #include "gui/widgets/settings.hpp"
39 #include "gui/widgets/text_box.hpp"
43 
44 #include "addon/manager_ui.hpp"
45 #include "formatter.hpp"
46 #include "formula/string_utils.hpp"
47 #include "preferences/game.hpp"
48 #include "gettext.hpp"
49 #include "preferences/lobby.hpp"
50 #include "playmp_controller.hpp"
51 #include "wesnothd_connection.hpp"
52 
53 #include "utils/functional.hpp"
54 
55 static lg::log_domain log_lobby("lobby");
56 #define DBG_LB LOG_STREAM(debug, log_lobby)
57 #define LOG_LB LOG_STREAM(info, log_lobby)
58 #define ERR_LB LOG_STREAM(err, log_lobby)
59 #define SCOPE_LB log_scope2(log_lobby, __func__)
60 
61 namespace gui2
62 {
63 namespace dialogs
64 {
65 
66 REGISTER_DIALOG(mp_lobby)
67 
68 void sub_player_list::init(window& w, const std::string& lbl, const bool unfolded)
69 {
70  tree_view& parent_tree = find_widget<tree_view>(&w, "player_tree", false);
71 
72  std::map<std::string, string_map> tree_group_item;
73  tree_group_item["tree_view_node_label"]["label"] = lbl;
74 
75  tree = &parent_tree.add_node("player_group", tree_group_item);
76 
77  if(unfolded) {
78  tree->unfold();
79  }
80 
81  tree_label = find_widget<label>(tree, "tree_view_node_label", false, true);
82  label_player_count = find_widget<label>(tree, "player_count", false, true);
83 
84  assert(tree_label);
85  assert(label_player_count);
86 }
87 
89 {
90  assert(tree);
91  assert(label_player_count);
92 
93  /**
94  * @todo Make sure setting visible resizes the widget.
95  *
96  * It doesn't work here since invalidate_layout is blocked, but the
97  * widget should also be able to handle it itself. Once done the
98  * setting of the label text can also be removed.
99  */
100  label_player_count->set_label((formatter() << "(" << tree->count_children() << ")").str());
101 }
102 
104 {
105  active_game.init(w, _("Selected Game"));
106  other_games.init(w, _("Other Games"));
107 #ifdef ENABLE_ROOM_MEMBER_TREE
108  active_room.init(w, _("Current Room"));
109 #endif
110  other_rooms.init(w, _("Lobby"), true);
111 
112  sort_by_name = find_widget<toggle_button>(&w, "player_list_sort_name", false, true);
113  sort_by_relation = find_widget<toggle_button>(&w, "player_list_sort_relation", false, true);
114 
115  tree = find_widget<tree_view>(&w, "player_tree", false, true);
116 }
117 
119 {
120  sort_by_name->set_icon_name(sort_by_name->get_value() ? "lobby/sort-az.png" : "lobby/sort-az-off.png");
121  sort_by_relation->set_icon_name(sort_by_relation->get_value() ? "lobby/sort-friend.png" : "lobby/sort-friend-off.png");
122 }
123 
125 {
126  return show_prompt(_("Do you really want to log out?"));
127 }
128 
130  : quit_confirmation(&mp_lobby::logout_prompt)
131  , game_config_(game_config)
132  , gamelistbox_(nullptr)
133  , lobby_info_(info)
134  , chatbox_(nullptr)
135  , filter_friends_(nullptr)
136  , filter_ignored_(nullptr)
137  , filter_slots_(nullptr)
138  , filter_invert_(nullptr)
139  , filter_text_(nullptr)
140  , selected_game_id_()
141  , player_list_()
142  , player_list_dirty_(true)
143  , gamelist_dirty_(true)
144  , last_gamelist_update_(0)
145  , gamelist_diff_update_(true)
146  , network_connection_(connection)
147  , lobby_update_timer_(0)
148  , gamelist_id_at_row_()
149  , delay_playerlist_update_(false)
150  , delay_gamelist_update_(false)
151  , joined_game_id_(0)
152 {
153  // Need to set this in the constructor, pre_show() is too late
155  set_allow_plugin_skip(false);
156 }
157 
159 {
161  {
162  l.delay_gamelist_update_ = true;
163  }
165  {
166  l.delay_gamelist_update_ = false;
167  }
169 };
170 
172 {
173  if(lobby_update_timer_) {
175  }
176 }
177 
179 {
180  /** @todo Should become a global hotkey after 1.8, then remove it here. */
182  std::bind(&CVideo::toggle_fullscreen, std::ref(win.video())));
183 
184  /*** Local hotkeys. ***/
186  std::bind(&mp_lobby::show_preferences_button_callback, this, std::ref(win)));
187 }
188 
189 namespace
190 {
191 void modify_grid_with_data(grid* grid, const std::map<std::string, string_map>& map)
192 {
193  for(const auto& v : map) {
194  const std::string& key = v.first;
195  const string_map& strmap = v.second;
196 
197  widget* w = grid->find(key, false);
198  if(!w) {
199  continue;
200  }
201 
202  styled_widget* c = dynamic_cast<styled_widget*>(w);
203  if(!c) {
204  continue;
205  }
206 
207  for(const auto & vv : strmap) {
208  if(vv.first == "label") {
209  c->set_label(vv.second);
210  } else if(vv.first == "tooltip") {
211  c->set_tooltip(vv.second);
212  }
213  }
214  }
215 }
216 
217 std::string colorize(const std::string& str, const std::string& color)
218 {
219  if(color.empty()) {
220  return str;
221  }
222 
223  return (formatter() << "<span color=\"" << color << "\">" << str << "</span>").str();
224 }
225 
226 bool handle_addon_requirements_gui(const std::vector<mp::game_info::required_addon>& reqs, mp::game_info::ADDON_REQ addon_outcome)
227 {
228  if(addon_outcome == mp::game_info::CANNOT_SATISFY) {
229  std::string e_title = _("Incompatible User-made Content.");
230  std::string err_msg = _("This game cannot be joined because the host has out-of-date add-ons that are incompatible with your version. You might wish to suggest that the host's add-ons be updated.");
231 
232  err_msg +="\n\n";
233  err_msg += _("Details:");
234  err_msg += "\n";
235 
236  for(const mp::game_info::required_addon & a : reqs) {
237  if (a.outcome == mp::game_info::CANNOT_SATISFY) {
238  err_msg += font::unicode_bullet + " " + a.message + "\n";
239  }
240  }
241  gui2::show_message(e_title, err_msg, message::auto_close, true);
242 
243  return false;
244  } else if(addon_outcome == mp::game_info::NEED_DOWNLOAD) {
245  std::string e_title = _("Missing User-made Content.");
246  std::string err_msg = _("This game requires one or more user-made addons to be installed or updated in order to join.\nDo you want to try to install them?");
247 
248  err_msg +="\n\n";
249  err_msg += _("Details:");
250  err_msg += "\n";
251 
252  std::vector<std::string> needs_download;
253  for(const mp::game_info::required_addon & a : reqs) {
254  if(a.outcome == mp::game_info::NEED_DOWNLOAD) {
255  err_msg += font::unicode_bullet + " " + a.message + "\n";
256 
257  needs_download.push_back(a.addon_id);
258  }
259  }
260 
261  assert(needs_download.size() > 0);
262 
263  if(gui2::show_message(e_title, err_msg, message::yes_no_buttons, true) == gui2::window::OK) {
264  // Begin download session
265  return ad_hoc_addon_fetch_session(needs_download);
266  }
267  }
268 
269  return false;
270 }
271 
272 } // end anonymous namespace
273 
275 {
276  SCOPE_LB;
277  gamelistbox_->clear();
278  gamelist_id_at_row_.clear();
280 
281  int select_row = -1;
282  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
283  const mp::game_info& game = *lobby_info_.games()[i];
284 
285  if(game.id == selected_game_id_) {
286  select_row = i;
287  }
288 
289  gamelist_id_at_row_.push_back(game.id);
290  LOG_LB << "Adding game to listbox (1)" << game.id << "\n";
291  grid* grid = &gamelistbox_->add_row(make_game_row_data(game));
292 
293  adjust_game_row_contents(game, grid);
294  }
295 
296  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
297  gamelistbox_->select_row(select_row);
298  }
299 
301  gamelist_dirty_ = false;
302  last_gamelist_update_ = SDL_GetTicks();
307 }
308 
310 {
311  SCOPE_LB;
313  int select_row = -1;
314  unsigned list_i = 0;
315  int list_rows_deleted = 0;
316 
317  std::vector<int> next_gamelist_id_at_row;
318  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
319  const mp::game_info& game = *lobby_info_.games()[i];
320 
321  if(game.display_status == mp::game_info::NEW) {
322  LOG_LB << "Adding game to listbox " << game.id << "\n";
323 
324  if(list_i != gamelistbox_->get_item_count()) {
325  gamelistbox_->add_row(make_game_row_data(game), list_i);
326  DBG_LB << "Added a game listbox row not at the end" << list_i
327  << " " << gamelistbox_->get_item_count() << "\n";
328  list_rows_deleted--;
329  } else {
331  }
332 
334  adjust_game_row_contents(game, grid);
335 
336  list_i++;
337  next_gamelist_id_at_row.push_back(game.id);
338  } else {
339  if(list_i >= gamelistbox_->get_item_count()) {
340  ERR_LB << "Ran out of listbox items -- triggering a full refresh\n";
341  refresh_lobby();
342  return;
343  }
344 
345  if(list_i + list_rows_deleted >= gamelist_id_at_row_.size()) {
346  ERR_LB << "gamelist_id_at_row_ overflow! " << list_i << " + "
347  << list_rows_deleted
348  << " >= " << gamelist_id_at_row_.size()
349  << " -- triggering a full refresh\n";
350  refresh_lobby();
351  return;
352  }
353 
354  int listbox_game_id = gamelist_id_at_row_[list_i + list_rows_deleted];
355  if(game.id != listbox_game_id) {
356  ERR_LB << "Listbox game id does not match expected id "
357  << listbox_game_id << " " << game.id << " (row " << list_i << ")\n";
358  refresh_lobby();
359  return;
360  }
361 
363  LOG_LB << "Modifying game in listbox " << game.id << " (row " << list_i << ")\n";
364  grid* grid = gamelistbox_->get_row_grid(list_i);
365  modify_grid_with_data(grid, make_game_row_data(game));
366  adjust_game_row_contents(game, grid, false);
367  ++list_i;
368  next_gamelist_id_at_row.push_back(game.id);
369  } else if(game.display_status == mp::game_info::DELETED) {
370  LOG_LB << "Deleting game from listbox " << game.id << " (row "
371  << list_i << ")\n";
372  gamelistbox_->remove_row(list_i);
373  ++list_rows_deleted;
374  } else {
375  // clean
376  LOG_LB << "Clean game in listbox " << game.id << " (row " << list_i << ")\n";
377  next_gamelist_id_at_row.push_back(game.id);
378  ++list_i;
379  }
380  }
381  }
382 
383  for(unsigned i = 0; i < next_gamelist_id_at_row.size(); ++i) {
384  if(next_gamelist_id_at_row[i] == selected_game_id_) {
385  select_row = i;
386  }
387  }
388 
389  next_gamelist_id_at_row.swap(gamelist_id_at_row_);
390  if(select_row >= static_cast<int>(gamelistbox_->get_item_count())) {
391  ERR_LB << "Would select a row beyond the listbox" << select_row << " "
392  << gamelistbox_->get_item_count() << "\n";
393  select_row = gamelistbox_->get_item_count() - 1;
394  }
395 
396  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
397  gamelistbox_->select_row(select_row);
398  }
399 
401  gamelist_dirty_ = false;
402  last_gamelist_update_ = SDL_GetTicks();
407 }
408 
410 {
411 #ifndef GUI2_EXPERIMENTAL_LISTBOX
412  const std::string games_string = vgettext("Games: showing $num_shown out of $num_total", {
413  {"num_shown", std::to_string(lobby_info_.games_visibility().count())},
414  {"num_total", std::to_string(lobby_info_.games().size())}
415  });
416 
417  find_widget<label>(gamelistbox_, "map", false).set_label(games_string);
418 #endif
419 }
420 
421 std::map<std::string, string_map> mp_lobby::make_game_row_data(const mp::game_info& game)
422 {
423  std::map<std::string, string_map> data;
424  string_map item;
425 
426  item["use_markup"] = "true";
427 
428  std::string color_string;
429  if(game.vacant_slots > 0) {
430  color_string = (game.reloaded || game.started) ? "yellow" : "green";
431  }
432 
433  item["label"] = colorize("<i>" + game.name + "</i>", font::GRAY_COLOR.to_hex_string());
434  data.emplace("name", item);
435 
436  item["label"] = game.scenario;
437  data.emplace("scenario", item);
438 
439  item["label"] = colorize(game.status, color_string);
440  data.emplace("status", item);
441 
442  return data;
443 }
444 
445 void mp_lobby::adjust_game_row_contents(const mp::game_info& game, grid* grid, bool add_callbacks)
446 {
447  find_widget<styled_widget>(grid, "name", false).set_use_markup(true);
448  find_widget<styled_widget>(grid, "status", false).set_use_markup(true);
449 
450  toggle_panel& row_panel = find_widget<toggle_panel>(grid, "panel", false);
451 
452  //
453  // Game info
454  //
455  std::ostringstream ss;
456 
457  ss << "<big>" << _("Era:") << "</big>\n" << game.era << "\n";
458 
459  ss << "\n<big>" << _("Modifications:") << "</big>\n";
460 
461  std::vector<std::string> mods = utils::split(game.mod_info);
462 
463  if(mods.empty()) {
464  ss << _("None") << "\n";
465  } else {
466  for(const std::string& mod : mods) {
467  ss << mod << "\n";
468  }
469  }
470 
471  // TODO: move to some general are of the code.
472  const auto yes_or_no = [](bool val) { return val ? _("yes") : _("no"); };
473 
474  ss << "\n<big>" << _("Settings:") << "</big>\n";
475  ss << _("Experience modifier:") << " " << game.xp << "\n";
476  ss << _("Gold:") << " " << game.gold << "\n";
477  ss << _("Map size:") << " " << game.map_size_info << "\n";
478  ss << _("Registered users only:") << " " << yes_or_no(game.registered_users_only) << "\n";
479  ss << _("Reloaded:") << " " << yes_or_no(game.reloaded) << "\n";
480  ss << _("Shared vision:") << " " << game.vision << "\n";
481  ss << _("Shuffle sides:") << " " << yes_or_no(game.shuffle_sides) << "\n";
482  ss << _("Time limit:") << " " << game.time_limit << "\n";
483  ss << _("Use map settings:") << " " << yes_or_no(game.use_map_settings);
484 
485  image& info_icon = find_widget<image>(grid, "game_info", false);
486 
487  if(!game.have_era || !game.have_all_mods || !game.required_addons.empty()) {
488  info_icon.set_label("icons/icon-info-error.png");
489 
490  ss << "\n\n<big><span color='#f00'>! </span></big>";
491  ss << _("One or more items need to be installed\nin order to join this game.");
492  } else {
493  info_icon.set_label("icons/icon-info.png");
494  }
495 
496  info_icon.set_tooltip(ss.str());
497 
498  //
499  // Password icon
500  //
501  image& password_icon = find_widget<image>(grid, "needs_password", false);
502 
503  if(game.password_required) {
505  } else {
507  }
508 
509  //
510  // Observer icon
511  //
512  image& observer_icon = find_widget<image>(grid, "observer_icon", false);
513 
514  if(game.observers) {
515  observer_icon.set_label("misc/eye.png");
516  observer_icon.set_tooltip( _("Observers allowed"));
517  } else {
518  observer_icon.set_label("misc/no_observer.png");
519  observer_icon.set_tooltip( _("Observers not allowed"));
520  }
521 
522  //
523  // Minimap
524  //
525  minimap& map = find_widget<minimap>(grid, "minimap", false);
526 
527  map.set_config(&game_config_);
528  map.set_map_data(game.map_data);
529 
530  button& join_button = find_widget<button>(grid, "join", false);
531  button& observe_button = find_widget<button>(grid, "observe", false);
532 
533  join_button.set_active(game.can_join());
534  observe_button.set_active(game.can_observe());
535 
536  if(!add_callbacks) {
537  return;
538  }
539 
541  std::bind(&mp_lobby::enter_game_by_id, this, game.id, DO_EITHER));
542 
544  std::bind(&mp_lobby::enter_game_by_id, this, game.id, DO_JOIN));
545 
546  connect_signal_mouse_left_click(observe_button,
547  std::bind(&mp_lobby::enter_game_by_id, this, game.id, DO_OBSERVE));
548 }
549 
551 {
552  DBG_LB << "mp_lobby::update_gamelist_filter\n";
554  DBG_LB << "Games in lobby_info: " << lobby_info_.games().size()
555  << ", games in listbox: " << gamelistbox_->get_item_count() << "\n";
556  assert(lobby_info_.games().size() == gamelistbox_->get_item_count());
558 
560 }
561 
563 {
565  return;
566  }
567 
568  SCOPE_LB;
569  DBG_LB << "Playerlist update: " << lobby_info_.users().size() << "\n";
573 
574 #ifdef ENABLE_ROOM_MEMBER_TREE
575  bool lobby = false;
577  if(ri->name() == "lobby") {
578  lobby = true;
579  }
580  }
581 #endif
582 
583  assert(player_list_.active_game.tree);
584 #ifdef ENABLE_ROOM_MEMBER_TREE
585  assert(player_list_.active_room.tree);
586 #endif
587  assert(player_list_.other_games.tree);
588  assert(player_list_.other_rooms.tree);
589 
591 #ifdef ENABLE_ROOM_MEMBER_TREE
593 #endif
596 
597  for(auto userptr : lobby_info_.users_sorted()) {
598  mp::user_info& user = *userptr;
599  sub_player_list* target_list(nullptr);
600 
601  std::string name = user.name;
602 
603  std::stringstream icon_ss;
604  icon_ss << "lobby/status";
605  switch(user.state) {
606 #ifdef ENABLE_ROOM_MEMBER_TREE
608  icon_ss << "-lobby";
609  target_list = &player_list_.active_room;
610  if(lobby) {
611  target_list = &player_list_.other_rooms;
612  }
613  break;
614 #endif
616  icon_ss << "-lobby";
617  target_list = &player_list_.other_rooms;
618  break;
620  name = colorize(name, "cyan");
621  icon_ss << (user.observing ? "-obs" : "-playing");
622  target_list = &player_list_.active_game;
623  break;
624  case mp::user_info::GAME:
625  name = colorize(name, "red");
626  icon_ss << (user.observing ? "-obs" : "-playing");
627  target_list = &player_list_.other_games;
628  break;
629  default:
630  ERR_LB << "Bad user state in lobby: " << user.name << ": "
631  << user.state << "\n";
632  continue;
633  }
634 
635  switch(user.relation) {
636  case mp::user_info::ME:
637  icon_ss << "-s";
638  break;
640  icon_ss << "-n";
641  break;
643  icon_ss << "-f";
644  break;
646  icon_ss << "-i";
647  break;
648  default:
649  ERR_LB << "Bad user relation in lobby: " << user.relation
650  << "\n";
651  }
652 
653  if(user.registered) {
654  name = "<b>" + name + "</b>";
655  }
656 
657  icon_ss << ".png";
658 
660  target_list = &player_list_.other_rooms;
661  }
662 
663  assert(target_list->tree);
664 
665  string_map tree_group_field;
666  std::map<std::string, string_map> tree_group_item;
667 
668  /*** Add tree item ***/
669  tree_group_field["label"] = icon_ss.str();
670  tree_group_item["icon"] = tree_group_field;
671 
672  tree_group_field["label"] = name;
673  tree_group_field["use_markup"] = "true";
674  tree_group_item["name"] = tree_group_field;
675 
676  tree_view_node& player = target_list->tree->add_child("player", tree_group_item);
677 
678  connect_signal_mouse_left_double_click(find_widget<toggle_panel>(&player, "tree_view_node_label", false),
679  std::bind(&mp_lobby::user_dialog_callback, this, userptr));
680  }
681 
683 #ifdef ENABLE_ROOM_MEMBER_TREE
685 #endif
688 
689  player_list_dirty_ = false;
690 }
691 
693 {
694  const int idx = gamelistbox_->get_selected_row();
695  bool can_join = false, can_observe = false;
696 
697  if(idx >= 0) {
698  const mp::game_info& game = *lobby_info_.games()[idx];
699  can_observe = game.can_observe();
700  can_join = game.can_join();
701  selected_game_id_ = game.id;
702  } else {
703  selected_game_id_ = 0;
704  }
705 
706  find_widget<button>(get_window(), "observe_global", false).set_active(can_observe);
707  find_widget<button>(get_window(), "join_global", false).set_active(can_join);
708 
709  player_list_dirty_ = true;
710 }
711 
713 {
714  if(window.get_retval() == window::CANCEL) {
715  return quit();
716  }
717 
718  return true;
719 }
720 
722 {
723  SCOPE_LB;
724 
725  gamelistbox_ = find_widget<listbox>(&window, "game_list", false, true);
726 
728  std::bind(&mp_lobby::gamelist_change_callback, this));
729 
730  player_list_.init(window);
734 
736  std::bind(&mp_lobby::player_filter_callback, this));
737 
739  std::bind(&mp_lobby::player_filter_callback, this));
740 
741  window.set_enter_disabled(true);
742 
743  // Exit hook to add a confirmation when quitting the Lobby.
744  window.set_exit_hook(std::bind(&mp_lobby::exit_hook, this, std::ref(window)));
745 
746  chatbox_ = find_widget<chatbox>(&window, "chat", false, true);
747 
748  window.keyboard_capture(chatbox_);
749 
753 
754  find_widget<button>(&window, "create", false).set_retval(CREATE);
755 
757  find_widget<button>(&window, "refresh", false),
758  std::bind(&mp_lobby::refresh_lobby, this));
759 
761  find_widget<button>(&window, "show_preferences", false),
762  std::bind(&mp_lobby::show_preferences_button_callback, this, std::ref(window)));
763 
765  find_widget<button>(&window, "join_global", false),
766  std::bind(&mp_lobby::enter_selected_game, this, DO_JOIN));
767 
768  find_widget<button>(&window, "join_global", false).set_active(false);
769 
771  find_widget<button>(&window, "observe_global", false),
772  std::bind(&mp_lobby::enter_selected_game, this, DO_OBSERVE));
773 
774  find_widget<button>(&window, "observe_global", false).set_active(false);
775 
776  menu_button& replay_options = find_widget<menu_button>(&window, "replay_options", false);
777 
779  replay_options.set_selected(1);
780  }
781 
783  replay_options.set_selected(2);
784  }
785 
786  replay_options.connect_click_handler(
787  std::bind(&mp_lobby::skip_replay_changed_callback, this, std::ref(window)));
788 
789  filter_friends_ = find_widget<toggle_button>(&window, "filter_with_friends", false, true);
790  filter_ignored_ = find_widget<toggle_button>(&window, "filter_without_ignored", false, true);
791  filter_slots_ = find_widget<toggle_button>(&window, "filter_vacant_slots", false, true);
792  filter_invert_ = find_widget<toggle_button>(&window, "filter_invert", false, true);
793  filter_text_ = find_widget<text_box>(&window, "filter_text", false, true);
794 
796  std::bind(&mp_lobby::game_filter_change_callback, this));
797 
798  connect_signal_notify_modified(*filter_ignored_,
799  std::bind(&mp_lobby::game_filter_change_callback, this));
800 
801  connect_signal_notify_modified(*filter_slots_,
802  std::bind(&mp_lobby::game_filter_change_callback, this));
803 
804  connect_signal_notify_modified(*filter_invert_,
805  std::bind(&mp_lobby::game_filter_change_callback, this));
806 
808  *filter_text_,
809  std::bind(&mp_lobby::game_filter_keypress_callback, this, _5));
810 
811  chatbox_->room_window_open("lobby", true, false);
814 
815  // Force first update to be directly.
816  update_gamelist();
818 
819  // TODO: currently getting a crash in the chatbox if we use this.
820  // -- vultraz, 2017-11-10
821  //mp_lobby::network_handler();
822 
825 
826  // Set up Lua plugin context
827  plugins_context_.reset(new plugins_context("Multiplayer Lobby"));
828 
829  plugins_context_->set_callback("join", [&, this](const config&) {
831  }, true);
832 
833  plugins_context_->set_callback("observe", [&, this](const config&) {
835  }, true);
836 
837  plugins_context_->set_callback("create", [&window](const config&) { window.set_retval(CREATE); }, true);
838  plugins_context_->set_callback("quit", [&window](const config&) { window.set_retval(window::CANCEL); }, false);
839 
840  plugins_context_->set_callback("chat", [this](const config& cfg) { chatbox_->send_chat_message(cfg["message"], false); }, true);
841  plugins_context_->set_callback("select_game", [this](const config& cfg) {
842  selected_game_id_ = cfg.has_attribute("id") ? cfg["id"].to_int() : lobby_info_.games()[cfg["index"].to_int()]->id;
843  }, true);
844 
845  plugins_context_->set_accessor("game_list", [this](const config&) { return lobby_info_.gamelist(); });
846  plugins_context_->set_accessor("game_config", [this](const config&) { return game_config_; });
847 }
848 
849 void mp_lobby::post_show(window& /*window*/)
850 {
853  plugins_context_.reset();
854 }
855 
857 {
858  try {
859  config data;
860  if (network_connection_.receive_data(data)) {
861  process_network_data(data);
862  }
863  } catch (wesnothd_error& e) {
864  LOG_LB << "caught wesnothd_error in network_handler: " << e.message << "\n";
865  throw;
866  }
867 
871  } else {
872  update_gamelist();
873  gamelist_diff_update_ = true;
874  }
875  }
876 
877  if(player_list_dirty_) {
880  }
881 }
882 
884 {
885  if(const config& error = data.child("error")) {
886  throw wesnothd_error(error["message"]);
887  } else if(data.child("gamelist")) {
888  process_gamelist(data);
889  } else if(const config& gamelist_diff = data.child("gamelist_diff")) {
890  process_gamelist_diff(gamelist_diff);
891  }
892 
894 }
895 
897 {
899  DBG_LB << "Received gamelist\n";
900  gamelist_dirty_ = true;
901  gamelist_diff_update_ = false;
902 }
903 
905 {
907  DBG_LB << "Received gamelist diff\n";
908  gamelist_dirty_ = true;
909  } else {
910  ERR_LB << "process_gamelist_diff failed!" << std::endl;
911  refresh_lobby();
912  }
913  const int joined = data.child_count("insert_child");
914  const int left = data.child_count("remove_child");
915  if(joined > 0 || left > 0) {
916  if(left > joined) {
918  } else {
920  }
921  }
922 }
923 
925 {
926  const bool try_join = mode == DO_JOIN || (mode == DO_EITHER && game.can_join());
927  const bool try_obsv = mode == DO_OBSERVE;
928 
929  if(try_obsv && !game.can_observe()) {
930  ERR_LB << "Attempted to observe a game with observers disabled" << std::endl;
931  return;
932  }
933 
934  if(try_join && !game.can_join()) {
935  ERR_LB << "Attempted to join a game with no vacant slots" << std::endl;
936  return;
937  }
938 
939  window& window = *get_window();
940 
941  // Prompt user to download this game's required addons if its requirements have not been met
943  if(game.required_addons.empty()) {
944  gui2::show_error_message(_("Something is wrong with the addon version check database supporting the multiplayer lobby. Please report this at http://bugs.wesnoth.org."));
945  return;
946  }
947 
948  if(!handle_addon_requirements_gui(game.required_addons, game.addons_outcome)) {
949  return;
950  }
951 
952  // Addons have been downloaded, so the game_config and installed addons list need to be reloaded.
953  // The lobby is closed and reopened.
954  window.set_retval(RELOAD_CONFIG);
955  return;
956  }
957 
958  config response;
959 
960  config& join_data = response.add_child("join");
961  join_data["id"] = std::to_string(game.id);
962  join_data["observe"] = try_obsv;
963 
964  if(!join_data.empty() && try_join && game.password_required) {
966 
967  if(!gui2::dialogs::mp_join_game_password_prompt::execute(password)) {
968  return;
969  }
970 
971  join_data["password"] = password;
972  }
973 
974  network_connection_.send_data(response);
975  joined_game_id_ = game.id;
976 
977  // We're all good. Close lobby and proceed to game!
978  window.set_retval(try_join ? JOIN : OBSERVE);
979 }
980 
982 {
983  try {
984  enter_game(*lobby_info_.games().at(index), mode);
985  } catch(const std::out_of_range&) {
986  // Game index was invalid!
987  ERR_LB << "Attempted to join/observe a game with index out of range: " << index << ". "
988  << "Games vector size is " << lobby_info_.games().size() << std::endl;
989  }
990 }
991 
992 void mp_lobby::enter_game_by_id(const int game_id, JOIN_MODE mode)
993 {
994  mp::game_info* game_ptr = lobby_info_.get_game_by_id(game_id);
995 
996  if(!game_ptr) {
997  ERR_LB << "Attempted to join/observe a game with an invalid id: " << game_id << std::endl;
998  return;
999  }
1000 
1001  enter_game(*game_ptr, mode);
1002 }
1003 
1005 {
1007 }
1008 
1010 {
1011  network_connection_.send_data(config("refresh_lobby"));
1012 }
1013 
1015 {
1017 
1018  /**
1019  * The screen size might have changed force an update of the size.
1020  *
1021  * @todo This might no longer be needed when gui2 is done.
1022  */
1023  const SDL_Rect rect = window.video().screen_area();
1024 
1029 
1030  /**
1031  * The screen size might have changed force an update of the size.
1032  *
1033  * @todo This might no longer be needed when gui2 is done.
1034  */
1035  window.invalidate_layout();
1036 
1037  refresh_lobby();
1038 }
1039 
1041 {
1043 
1044  for(const auto& s : utils::split(filter_text_->get_value(), ' ')) {
1045  lobby_info_.add_game_filter([s](const mp::game_info& info)->bool {
1046  return info.match_string_filter(s);
1047  });
1048  }
1049 
1050  // TODO: make changing friend/ignore lists trigger a refresh
1051  if(filter_friends_->get_value()) {
1052  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1053  return info.has_friends == true;
1054  });
1055  }
1056 
1057  if(filter_ignored_->get_value()) {
1058  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1059  return info.has_ignored == false;
1060  });
1061  }
1062 
1063  if(filter_slots_->get_value()) {
1064  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1065  return info.vacant_slots > 0;
1066  });
1067  }
1068 
1070 }
1071 
1072 void mp_lobby::game_filter_keypress_callback(const SDL_Keycode key)
1073 {
1074  if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1077  }
1078 }
1079 
1081 {
1084 }
1085 
1087 {
1089 }
1090 
1092 {
1094 
1097 
1098  player_list_dirty_ = true;
1099  // get_window()->invalidate_layout();
1100 }
1101 
1103 {
1104  lobby_player_info dlg(*chatbox_, *info, lobby_info_);
1105 
1107 
1108  dlg.show();
1109 
1110  delay_playerlist_update_ = true;
1111 
1112  if(dlg.result_open_whisper()) {
1115  }
1116 
1117  selected_game_id_ = info->game_id;
1118 
1119  // do not update here as it can cause issues with removing the widget
1120  // from within it's event handler. Should get updated as soon as possible
1121  // update_gamelist();
1122  delay_playerlist_update_ = false;
1123  player_list_dirty_ = true;
1124  refresh_lobby();
1125 }
1126 
1128 {
1129  // TODO: this prefence should probably be controlled with an enum
1130  const int value = find_widget<menu_button>(&window, "replay_options", false).get_value();
1131  preferences::set_skip_mp_replay(value == 1);
1133 }
1134 
1135 } // namespace dialogs
1136 } // namespace gui2
Define the common log macros for the gui toolkit.
void game_filter_keypress_callback(const SDL_Keycode key)
Definition: lobby.cpp:1072
const std::vector< game_info * > & games() const
Definition: lobby_info.hpp:132
void send_data(const configr_of &request)
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
Definition: chatbox.cpp:109
void active_window_changed()
Definition: chatbox.cpp:94
An error occurred during when trying to coommunicate with the wesnothd server.
Class for a toggle button.
std::string scenario
Definition: lobby_data.hpp:147
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:152
std::string map_size_info
Definition: lobby_data.hpp:150
Dialog is closed with ok button.
Definition: window.hpp:101
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:417
const std::vector< user_info > & users() const
Definition: lobby_info.hpp:142
void set_map_data(const std::string &map_data)
Definition: minimap.hpp:60
ADDON_REQ addons_outcome
Definition: lobby_data.hpp:197
std::vector< char_t > string
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
void set_lobby_info(mp::lobby_info &i)
Definition: chatbox.hpp:85
void set_value(unsigned selected, bool fire_event=false) override
Inherited from selectable_item.
std::string status
Definition: lobby_data.hpp:159
#define ERR_LB
Definition: lobby.cpp:58
void connect_click_handler(const event::signal_function &signal)
Inherited from clickable_item.
Definition: menu_button.hpp:58
std::string mod_info
Definition: lobby_data.hpp:153
std::vector< int > gamelist_id_at_row_
Definition: lobby.hpp:214
void enter_game_by_index(const int index, JOIN_MODE mode)
Entry wrapper for enter_game, where game is located by index.
Definition: lobby.cpp:981
Simple push button.
Definition: menu_button.hpp:41
const color_t GRAY_COLOR
void init(window &w, const std::string &label, const bool unfolded=false)
Definition: lobby.cpp:68
bool match_string_filter(const std::string &filter) const
Definition: lobby_data.cpp:550
text_box * filter_text_
Definition: lobby.hpp:195
sub_player_list active_room
Definition: lobby.hpp:60
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:188
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
logger & info()
Definition: log.cpp:91
#define a
This class represents the info a client has about a game on the server.
Definition: lobby_data.hpp:137
user_state state
Definition: lobby_data.hpp:129
size_t lobby_update_timer_
Timer for updating the lobby.
Definition: lobby.hpp:212
bool can_join() const
Definition: lobby_data.cpp:523
#define DBG_LB
Definition: lobby.cpp:56
virtual void pre_show(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:721
size_t add_timer(const uint32_t interval, const std::function< void(size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:111
void update_user_statuses(int game_id, const room_info *room)
Definition: lobby_info.cpp:370
Base class for all widgets.
Definition: widget.hpp:48
void set_playerlist_sort_name(bool v)
Definition: lobby.cpp:50
This class represents the collective information the client has about the players and games on the se...
Definition: lobby_info.hpp:30
static bool show_prompt(const std::string &message)
void skip_replay_changed_callback(window &window)
Definition: lobby.cpp:1127
void add_game_filter(game_filter_func func)
Adds a new filter function to be considered when apply_game_filter is called.
Definition: lobby_info.hpp:67
bool remove_timer(const size_t id)
Removes a timer.
Definition: timer.cpp:143
unsigned get_value() const override
Inherited from selectable_item.
void user_dialog_callback(mp::user_info *info)
Definition: lobby.cpp:1102
STL namespace.
void adjust_game_row_contents(const mp::game_info &game, grid *grid, bool add_callbacks=true)
Definition: lobby.cpp:445
std::string get_value() const
#define LOG_LB
Definition: lobby.cpp:57
static bool logout_prompt()
Definition: lobby.cpp:124
unsigned gamemap_width
The size of the map area, if not available equal to the screen size.
Definition: settings.cpp:30
bool receive_data(config &result)
size_t vacant_slots
Definition: lobby_data.hpp:161
void process_network_data(const config &data)
Definition: lobby.cpp:883
void update_selected_game()
Definition: lobby.cpp:692
bool empty() const
Definition: config.cpp:828
void enter_selected_game(JOIN_MODE mode)
Enter game by index, where index is the selected game listbox row.
Definition: lobby.cpp:1004
bool show(const unsigned auto_close_time=0)
Shows the window.
std::string name
Definition: lobby_data.hpp:146
void process_gamelist(const config &data)
Process a full game list.
Definition: lobby_info.cpp:111
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
std::string time_limit
Definition: lobby_data.hpp:160
void apply_game_filter()
Generates a new list of games that match the current filter functions and inversion setting...
Definition: lobby_info.cpp:345
toggle_button * sort_by_name
Definition: lobby.hpp:64
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:252
static lg::log_domain log_lobby("lobby")
void update_gamelist_header()
Definition: lobby.cpp:409
Generic file dialog.
Definition: field-fwd.hpp:22
void set_playerlist_sort_relation(bool v)
Definition: lobby.cpp:40
void gamelist_change_callback()
Definition: lobby.cpp:1086
game_info * get_game_by_id(int id)
Returns info on a game with the given game ID.
Definition: lobby_info.cpp:264
void make_games_vector()
Generates a new vector of game pointers from the ID/game map.
Definition: lobby_info.cpp:330
virtual void set_label(const t_string &label)
sub_player_list other_rooms
Definition: lobby.hpp:61
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:274
unsigned child_count(config_key_type key) const
Definition: config.cpp:388
Base container class.
Definition: grid.hpp:30
bool password_required
Definition: lobby_data.hpp:173
listbox * gamelistbox_
Definition: lobby.hpp:181
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:56
const std::vector< user_info * > & users_sorted() const
Definition: lobby_info.hpp:147
void set_active_window_changed_callback(const std::function< void(void)> &f)
Definition: chatbox.hpp:80
void enter_game_by_id(const int game_id, JOIN_MODE mode)
Entry wrapper for enter_game, where game is located by game id.
Definition: lobby.cpp:992
void set_tooltip(const t_string &tooltip)
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:233
window * get_window() const
Returns a pointer to the dialog's window.
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:97
This file contains the settings handling of the widget library.
bool ad_hoc_addon_fetch_session(const std::vector< std::string > &addon_ids)
Conducts an ad-hoc add-ons server connection to download an add-on with a particular id and all it's ...
Definition: manager_ui.cpp:257
void init(window &w)
Definition: lobby.cpp:103
void set_show_even_without_video(const bool show_even_without_video)
std::ostringstream wrapper.
Definition: formatter.hpp:38
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:127
std::unique_ptr< plugins_context > plugins_context_
void set_visible(const visibility visible)
Definition: widget.cpp:479
unsigned lobby_network_timer
Implements a quit confirmation dialog.
void sync_games_display_status()
Definition: lobby_info.cpp:243
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:218
unsigned gamemap_height
Definition: settings.cpp:31
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:35
lobby_chat_window * whisper_window_open(const std::string &name, bool open_new)
Check if a whisper window for user "name" is open, if open_new is true then it will be created if not...
Definition: chatbox.cpp:362
std::string vision
Definition: lobby_data.hpp:158
bool blindfold_replay()
Definition: game.cpp:606
A class that represents a TCP/IP connection to the wesnothd server.
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:217
void update_gamelist_filter()
Definition: lobby.cpp:550
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:655
mp_lobby(const config &game_config, mp::lobby_info &info, wesnothd_connection &connection)
Definition: lobby.cpp:129
std::string map_data
Definition: lobby_data.hpp:145
void set_game_filter_invert(bool value)
Sets whether the result of each game filter should be inverted.
Definition: lobby_info.hpp:79
Shows a yes and no button.
Definition: message.hpp:79
void player_filter_callback()
Definition: lobby.cpp:1091
void process_gamelist_diff(const config &data)
Definition: lobby.cpp:904
void update_gamelist_diff()
Definition: lobby.cpp:309
std::string gold
Definition: lobby_data.hpp:155
void set_blindfold_replay(bool value)
Definition: game.cpp:611
void connect_signal_mouse_left_double_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button double click.
Definition: dispatcher.cpp:228
bool can_observe() const
Definition: lobby_data.cpp:528
tree_view_node & add_child(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Adds a child item to the list of child nodes.
std::map< std::string, string_map > make_game_row_data(const mp::game_info &game)
Definition: lobby.cpp:421
Various uncategorised dialogs.
CVideo & video()
Definition: window.hpp:381
static bool quit()
Shows the quit confirmation if needed.
int get_retval()
Definition: window.hpp:399
bool registered_users_only
Definition: lobby_data.hpp:171
mp::room_info * active_window_room()
Get the room* corresponding to the currently active window, or nullptr if a whisper window is active ...
Definition: chatbox.cpp:567
void process_network_data(const ::config &data)
Definition: chatbox.cpp:721
void set_config(const ::config *terrain)
Definition: minimap.hpp:78
bool use_map_settings
Definition: lobby_data.hpp:170
std::string name
Definition: lobby_data.hpp:126
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
void clear()
Removes all child items from the widget.
void show_preferences_button_callback(window &window)
Definition: lobby.cpp:1014
size_t count_children() const
The number of children in this widget.
static void display(const config &game_cfg, const preferences::PREFERENCE_VIEW initial_view=preferences::VIEW_DEFAULT)
The display function – see modal_dialog for more information.
bool playerlist_sort_relation()
Definition: lobby.cpp:35
void network_handler()
Network polling callback.
Definition: lobby.cpp:856
void enter_game(const mp::game_info &game, JOIN_MODE mode)
Exits the lobby and enters the given game.
Definition: lobby.cpp:924
Game configuration data as global variables.
Definition: build_info.cpp:53
void toggle_fullscreen()
Definition: video.cpp:552
static map_location::DIRECTION s
double g
Definition: astarsearch.cpp:64
std::string password(const std::string &server, const std::string &login)
void game_filter_change_callback()
Definition: lobby.cpp:1080
size_t i
Definition: function.cpp:933
Contains the gui2 timer routines.
toggle_button * filter_invert_
Definition: lobby.hpp:193
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
void unfold(const bool recursive=false)
grid & add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:68
unsigned screen_width
The screen resolution should be available for all widgets since their drawing method will depend on i...
Definition: settings.cpp:25
This class represents the information a client has about a room.
Definition: lobby_data.hpp:66
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:239
int w
void set_skip_mp_replay(bool value)
Definition: game.cpp:601
sub_player_list other_games
Definition: lobby.hpp:62
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:392
Base class for all visible items.
const std::string unicode_bullet
Definition: constants.cpp:42
bool skip_mp_replay()
Definition: game.cpp:596
player_list player_list_
Definition: lobby.hpp:199
The basic minimap class.
Definition: minimap.hpp:39
void process_gamelist(const config &data)
Definition: lobby.cpp:896
unsigned last_gamelist_update_
Definition: lobby.hpp:205
void clear_game_filter()
Clears all game filter functions.
Definition: lobby_info.hpp:73
bool process_gamelist_diff(const config &data)
Process a gamelist diff.
Definition: lobby_info.cpp:131
config & add_child(config_key_type key)
Definition: config.cpp:473
std::string era
Definition: lobby_data.hpp:151
std::string vgettext(const char *msgid, const utils::string_map &symbols)
bool grid()
Definition: general.cpp:507
This class represents the information a client has about another player.
Definition: lobby_data.hpp:103
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:62
bool get_value_bool() const
tree_view_node * tree
Definition: lobby.hpp:50
virtual void post_build(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:178
The user sets the widget visible, that means:
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard_function &signal)
Connects the signal for 'snooping' on the keypress.
Definition: dispatcher.cpp:213
void set_allow_plugin_skip(const bool allow_plugin_skip)
double t
Definition: astarsearch.cpp:64
unsigned screen_height
Definition: settings.cpp:26
The user sets the widget hidden, that means:
sub_player_list active_game
Definition: lobby.hpp:59
lu_byte left
Definition: lparser.cpp:1026
toggle_button * sort_by_relation
Definition: lobby.hpp:65
void set_wesnothd_connection(wesnothd_connection &c)
Definition: chatbox.hpp:90
unsigned lobby_refresh
this module manages the cache of images.
Definition: image.cpp:103
Simple push button.
Definition: button.hpp:35
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:88
std::string message
Definition: exceptions.hpp:31
wesnothd_connection & network_connection_
Definition: lobby.hpp:209
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:133
game_display_status display_status
Definition: lobby_data.hpp:186
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:803
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
Definition: video.cpp:295
std::vector< required_addon > required_addons
Definition: lobby_data.hpp:196
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:205
#define e
void sort_users(bool by_name, bool by_relation)
Sorts the user list by the given parameters.
Definition: lobby_info.cpp:377
mp::lobby_info & lobby_info_
Definition: lobby.hpp:183
void set_selected(int selected, bool fire_event=true)
user_relation relation
Definition: lobby_data.hpp:128
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
const boost::dynamic_bitset & games_visibility() const
Definition: lobby_info.hpp:137
mock_char c
Enables auto close.
Definition: message.hpp:69
virtual void post_show(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:849
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:145
Dialog is closed with the cancel button.
Definition: window.hpp:102
toggle_button * filter_ignored_
Definition: lobby.hpp:189
lobby_chat_window * room_window_open(const std::string &room, const bool open_new, const bool allow_close=true)
Check if a room window for "room" is open, if open_new is true then it will be created if not found...
Definition: chatbox.cpp:357
bool exit_hook(window &window)
Definition: lobby.cpp:712
tree_view_node & add_node(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Definition: tree_view.cpp:62
const config & gamelist() const
Returns the raw game list config data.
Definition: lobby_info.hpp:59
toggle_button * filter_friends_
Definition: lobby.hpp:187
bool playerlist_sort_name()
Definition: lobby.cpp:45
std::string xp
Definition: lobby_data.hpp:157
bool playerlist_group_players()
Definition: lobby.cpp:55
const config & game_config_
Definition: lobby.hpp:179
toggle_button * filter_slots_
Definition: lobby.hpp:191
void set_icon_name(const std::string &icon_name)
#define SCOPE_LB
Definition: lobby.cpp:59