The Battle for Wesnoth  1.15.2+dev
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 https://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 
24 #include "gui/core/log.hpp"
25 #include "gui/core/timer.hpp"
26 #include "gui/widgets/button.hpp"
27 #include "gui/widgets/image.hpp"
28 #include "gui/widgets/label.hpp"
29 #include "gui/widgets/listbox.hpp"
31 #include "gui/widgets/minimap.hpp"
32 #include "gui/widgets/chatbox.hpp"
33 #include "gui/widgets/settings.hpp"
34 #include "gui/widgets/text_box.hpp"
38 
39 #include "addon/client.hpp"
40 #include "addon/manager_ui.hpp"
41 #include "chat_log.hpp"
42 #include "font/text_formatting.hpp"
43 #include "formatter.hpp"
44 #include "formula/string_utils.hpp"
45 #include "preferences/game.hpp"
46 #include "gettext.hpp"
47 #include "preferences/lobby.hpp"
48 #include "playmp_controller.hpp"
49 #include "wesnothd_connection.hpp"
50 
51 #include "utils/functional.hpp"
52 
53 static lg::log_domain log_lobby("lobby");
54 #define DBG_LB LOG_STREAM(debug, log_lobby)
55 #define LOG_LB LOG_STREAM(info, log_lobby)
56 #define ERR_LB LOG_STREAM(err, log_lobby)
57 #define SCOPE_LB log_scope2(log_lobby, __func__)
58 
59 namespace gui2
60 {
61 namespace dialogs
62 {
63 
64 REGISTER_DIALOG(mp_lobby)
65 
66 void sub_player_list::init(window& w, const std::string& lbl, const bool unfolded)
67 {
68  tree_view& parent_tree = find_widget<tree_view>(&w, "player_tree", false);
69 
70  std::map<std::string, string_map> tree_group_item;
71  tree_group_item["tree_view_node_label"]["label"] = lbl;
72 
73  tree = &parent_tree.add_node("player_group", tree_group_item);
74 
75  if(unfolded) {
76  tree->unfold();
77  }
78 
79  tree_label = find_widget<label>(tree, "tree_view_node_label", false, true);
80  label_player_count = find_widget<label>(tree, "player_count", false, true);
81 
82  assert(tree_label);
83  assert(label_player_count);
84 }
85 
87 {
88  assert(tree);
89  assert(label_player_count);
90 
91  /**
92  * @todo Make sure setting visible resizes the widget.
93  *
94  * It doesn't work here since invalidate_layout is blocked, but the
95  * widget should also be able to handle it itself. Once done the
96  * setting of the label text can also be removed.
97  */
98  label_player_count->set_label((formatter() << "(" << tree->count_children() << ")").str());
99 }
100 
102 {
103  active_game.init(w, _("Selected Game"), true);
104  other_rooms.init(w, _("Lobby"), true);
105 #ifdef ENABLE_ROOM_MEMBER_TREE
106  active_room.init(w, _("Current Room"));
107 #endif
108  other_games.init(w, _("Other Games"));
109 
110  tree = find_widget<tree_view>(&w, "player_tree", false, true);
111 }
112 
114 {
115  return show_prompt(_("Do you really want to log out?"));
116 }
117 
119  : quit_confirmation(&mp_lobby::logout_prompt)
120  , game_config_(game_config)
121  , gamelistbox_(nullptr)
122  , lobby_info_(info)
123  , chatbox_(nullptr)
124  , filter_friends_(nullptr)
125  , filter_ignored_(nullptr)
126  , filter_slots_(nullptr)
127  , filter_invert_(nullptr)
128  , filter_text_(nullptr)
129  , selected_game_id_()
130  , player_list_()
131  , player_list_dirty_(true)
132  , gamelist_dirty_(true)
133  , last_lobby_update_(0)
134  , gamelist_diff_update_(true)
135  , network_connection_(connection)
136  , lobby_update_timer_(0)
137  , gamelist_id_at_row_()
138  , delay_playerlist_update_(false)
139  , delay_gamelist_update_(false)
140  , joined_game_id_(0)
141 {
142  // Need to set this in the constructor, pre_show() is too late
144  set_allow_plugin_skip(false);
145 }
146 
148 {
150  {
151  l.delay_gamelist_update_ = true;
152  }
154  {
155  l.delay_gamelist_update_ = false;
156  }
158 };
159 
161 {
162  if(lobby_update_timer_) {
164  }
165 }
166 
168 {
169  /*** Local hotkeys. ***/
171  std::bind(&mp_lobby::show_preferences_button_callback, this, std::ref(win)));
172 }
173 
174 namespace
175 {
176 void modify_grid_with_data(grid* grid, const std::map<std::string, string_map>& map)
177 {
178  for(const auto& v : map) {
179  const std::string& key = v.first;
180  const string_map& strmap = v.second;
181 
182  widget* w = grid->find(key, false);
183  if(!w) {
184  continue;
185  }
186 
187  styled_widget* c = dynamic_cast<styled_widget*>(w);
188  if(!c) {
189  continue;
190  }
191 
192  for(const auto & vv : strmap) {
193  if(vv.first == "label") {
194  c->set_label(vv.second);
195  } else if(vv.first == "tooltip") {
196  c->set_tooltip(vv.second);
197  }
198  }
199  }
200 }
201 
202 std::string colorize(const std::string& str, const color_t& color)
203 {
204  return (formatter() << font::span_color(color) << str << "</span>").str();
205 }
206 
207 bool handle_addon_requirements_gui(const std::vector<mp::game_info::required_addon>& reqs, mp::game_info::ADDON_REQ addon_outcome)
208 {
209  if(addon_outcome == mp::game_info::CANNOT_SATISFY) {
210  std::string e_title = _("Incompatible User-made Content.");
211  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.");
212 
213  err_msg +="\n\n";
214  err_msg += _("Details:");
215  err_msg += "\n";
216 
217  for(const mp::game_info::required_addon & a : reqs) {
218  if (a.outcome == mp::game_info::CANNOT_SATISFY) {
219  err_msg += font::unicode_bullet + " " + a.message + "\n";
220  }
221  }
222  gui2::show_message(e_title, err_msg, message::auto_close, true);
223 
224  return false;
225  } else if(addon_outcome == mp::game_info::NEED_DOWNLOAD) {
226  std::string e_title = _("Missing User-made Content.");
227  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?");
228 
229  err_msg +="\n\n";
230  err_msg += _("Details:");
231  err_msg += "\n";
232 
233  std::vector<std::string> needs_download;
234  for(const mp::game_info::required_addon & a : reqs) {
235  if(a.outcome == mp::game_info::NEED_DOWNLOAD) {
236  err_msg += font::unicode_bullet + " " + a.message + "\n";
237 
238  needs_download.push_back(a.addon_id);
239  }
240  }
241 
242  assert(needs_download.size() > 0);
243 
244  if(gui2::show_message(e_title, err_msg, message::yes_no_buttons, true) == gui2::retval::OK) {
245  // Begin download session
246  try {
247  return ad_hoc_addon_fetch_session(needs_download);
248  } catch (const addons_client::user_exit&) {
249  } catch (const addons_client::user_disconnect&) {
250  }
251  }
252  }
253 
254  return false;
255 }
256 
257 } // end anonymous namespace
258 
260 {
261  SCOPE_LB;
262  gamelistbox_->clear();
263  gamelist_id_at_row_.clear();
265 
266  int select_row = -1;
267  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
268  const mp::game_info& game = *lobby_info_.games()[i];
269 
270  if(game.id == selected_game_id_) {
271  select_row = i;
272  }
273 
274  gamelist_id_at_row_.push_back(game.id);
275  LOG_LB << "Adding game to listbox (1)" << game.id << "\n";
277 
278  adjust_game_row_contents(game, grid);
279  }
280 
281  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
282  gamelistbox_->select_row(select_row);
283  }
284 
286  gamelist_dirty_ = false;
287  last_lobby_update_ = SDL_GetTicks();
292 }
293 
295 {
296  SCOPE_LB;
298  int select_row = -1;
299  unsigned list_i = 0;
300  int list_rows_deleted = 0;
301 
302  std::vector<int> next_gamelist_id_at_row;
303  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
304  const mp::game_info& game = *lobby_info_.games()[i];
305 
306  if(game.display_status == mp::game_info::NEW) {
307  // call void do_notify(notify_mode mode, const std::string& sender, const std::string& message)
308  // sender will be the game_info.scenario (std::string) and message will be game_info.name (std::string)
310 
311  LOG_LB << "Adding game to listbox " << game.id << "\n";
312 
313  if(list_i != gamelistbox_->get_item_count()) {
314  gamelistbox_->add_row(make_game_row_data(game), list_i);
315  DBG_LB << "Added a game listbox row not at the end" << list_i
316  << " " << gamelistbox_->get_item_count() << "\n";
317  list_rows_deleted--;
318  } else {
320  }
321 
323  adjust_game_row_contents(game, grid);
324 
325  list_i++;
326  next_gamelist_id_at_row.push_back(game.id);
327  } else {
328  if(list_i >= gamelistbox_->get_item_count()) {
329  ERR_LB << "Ran out of listbox items -- triggering a full refresh\n";
330  refresh_lobby();
331  return;
332  }
333 
334  if(list_i + list_rows_deleted >= gamelist_id_at_row_.size()) {
335  ERR_LB << "gamelist_id_at_row_ overflow! " << list_i << " + "
336  << list_rows_deleted
337  << " >= " << gamelist_id_at_row_.size()
338  << " -- triggering a full refresh\n";
339  refresh_lobby();
340  return;
341  }
342 
343  int listbox_game_id = gamelist_id_at_row_[list_i + list_rows_deleted];
344  if(game.id != listbox_game_id) {
345  ERR_LB << "Listbox game id does not match expected id "
346  << listbox_game_id << " " << game.id << " (row " << list_i << ")\n";
347  refresh_lobby();
348  return;
349  }
350 
352  LOG_LB << "Modifying game in listbox " << game.id << " (row " << list_i << ")\n";
353  grid* grid = gamelistbox_->get_row_grid(list_i);
354  modify_grid_with_data(grid, make_game_row_data(game));
355  adjust_game_row_contents(game, grid, false);
356  ++list_i;
357  next_gamelist_id_at_row.push_back(game.id);
358  } else if(game.display_status == mp::game_info::DELETED) {
359  LOG_LB << "Deleting game from listbox " << game.id << " (row "
360  << list_i << ")\n";
361  gamelistbox_->remove_row(list_i);
362  ++list_rows_deleted;
363  } else {
364  // clean
365  LOG_LB << "Clean game in listbox " << game.id << " (row " << list_i << ")\n";
366  next_gamelist_id_at_row.push_back(game.id);
367  ++list_i;
368  }
369  }
370  }
371 
372  for(unsigned i = 0; i < next_gamelist_id_at_row.size(); ++i) {
373  if(next_gamelist_id_at_row[i] == selected_game_id_) {
374  select_row = i;
375  }
376  }
377 
378  next_gamelist_id_at_row.swap(gamelist_id_at_row_);
379  if(select_row >= static_cast<int>(gamelistbox_->get_item_count())) {
380  ERR_LB << "Would select a row beyond the listbox" << select_row << " "
381  << gamelistbox_->get_item_count() << "\n";
382  select_row = gamelistbox_->get_item_count() - 1;
383  }
384 
385  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
386  gamelistbox_->select_row(select_row);
387  }
388 
390  gamelist_dirty_ = false;
391  last_lobby_update_ = SDL_GetTicks();
396 }
397 
399 {
400  const std::string games_string = VGETTEXT("Games: showing $num_shown out of $num_total", {
401  {"num_shown", std::to_string(lobby_info_.games_visibility().count())},
402  {"num_total", std::to_string(lobby_info_.games().size())}
403  });
404 
405  find_widget<label>(gamelistbox_, "map", false).set_label(games_string);
406 }
407 
408 std::map<std::string, string_map> mp_lobby::make_game_row_data(const mp::game_info& game)
409 {
410  std::map<std::string, string_map> data;
412 
413  item["use_markup"] = "true";
414 
415  color_t color_string;
416  if(game.vacant_slots > 0) {
417  color_string = (game.reloaded || game.started) ? font::YELLOW_COLOR : font::GOOD_COLOR;
418  }
419 
420  const std::string scenario_text = VGETTEXT("$game_name (Era: $era_name)", {
421  {"game_name", game.scenario},
422  {"era_name", game.era}
423  });
424 
425  item["label"] = game.vacant_slots > 0 ? colorize(game.name, color_string) : game.name;
426  data.emplace("name", item);
427 
428  item["label"] = colorize("<i>" + scenario_text + "</i>", font::GRAY_COLOR);
429  data.emplace("scenario", item);
430 
431  item["label"] = colorize(game.status, color_string);
432  data.emplace("status", item);
433 
434  return data;
435 }
436 
438 {
439  find_widget<styled_widget>(grid, "name", false).set_use_markup(true);
440  find_widget<styled_widget>(grid, "status", false).set_use_markup(true);
441 
442  toggle_panel& row_panel = find_widget<toggle_panel>(grid, "panel", false);
443 
444  //
445  // Game info
446  //
447  std::ostringstream ss;
448 
449  const auto mark_missing = [&ss]() {
450  ss << ' ' << font::span_color(font::BAD_COLOR) << "(" << _("era_or_mod^not installed") << ")</span>";
451  };
452 
453  ss << "<big>" << colorize(_("Era"), font::TITLE_COLOR) << "</big>\n" << game.era;
454 
455  if(!game.have_era) {
456  // NOTE: not using colorize() here deliberately to avoid awkward string concatenation.
457  mark_missing();
458  }
459 
460  ss << "\n\n<big>" << colorize(_("Modifications"), font::TITLE_COLOR) << "</big>\n";
461 
462  auto mods = game.mod_info;
463 
464  if(mods.empty()) {
465  ss << _("active_modifications^None") << "\n";
466  } else {
467  for(const auto& mod : mods) {
468  ss << mod.first;
469 
470  if(!mod.second) {
471  mark_missing();
472  }
473 
474  ss << '\n';
475  }
476  }
477 
478  // TODO: move to some general area of the code.
479  const auto yes_or_no = [](bool val) { return val ? _("yes") : _("no"); };
480 
481  ss << "\n<big>" << colorize(_("Settings"), font::TITLE_COLOR) << "</big>\n";
482  ss << _("Experience modifier:") << " " << game.xp << "\n";
483  ss << _("Gold per village:") << " " << game.gold << "\n";
484  ss << _("Map size:") << " " << game.map_size_info << "\n";
485  ss << _("Reloaded:") << " " << yes_or_no(game.reloaded) << "\n";
486  ss << _("Shared vision:") << " " << game.vision << "\n";
487  ss << _("Shuffle sides:") << " " << yes_or_no(game.shuffle_sides) << "\n";
488  ss << _("Time limit:") << " " << game.time_limit << "\n";
489  ss << _("Use map settings:") << " " << yes_or_no(game.use_map_settings);
490 
491  image& info_icon = find_widget<image>(grid, "game_info", false);
492 
493  if(!game.have_era || !game.have_all_mods || !game.required_addons.empty()) {
494  info_icon.set_label("icons/icon-info-error.png");
495 
496  ss << "\n\n<span color='#f00' size='x-large'>! </span>";
497  ss << _("One or more add-ons need to be installed\nin order to join this game.");
498  } else {
499  info_icon.set_label("icons/icon-info.png");
500  }
501 
502  info_icon.set_tooltip(ss.str());
503 
504  //
505  // Password icon
506  //
507  image& password_icon = find_widget<image>(grid, "needs_password", false);
508 
509  if(game.password_required) {
511  } else {
513  }
514 
515  //
516  // Observer icon
517  //
518  image& observer_icon = find_widget<image>(grid, "observer_icon", false);
519 
520  if(game.observers) {
521  observer_icon.set_label("misc/eye.png");
522  observer_icon.set_tooltip( _("Observers allowed"));
523  } else {
524  observer_icon.set_label("misc/no_observer.png");
525  observer_icon.set_tooltip( _("Observers not allowed"));
526  }
527 
528  //
529  // Minimap
530  //
531  minimap& map = find_widget<minimap>(grid, "minimap", false);
532 
533  map.set_config(&game_config_);
534  map.set_map_data(game.map_data);
535 
536  if(!add_callbacks) {
537  return;
538  }
539 
541  std::bind(&mp_lobby::enter_game_by_id, this, game.id, DO_EITHER));
542 }
543 
545 {
546  DBG_LB << "mp_lobby::update_gamelist_filter\n";
548  DBG_LB << "Games in lobby_info: " << lobby_info_.games().size()
549  << ", games in listbox: " << gamelistbox_->get_item_count() << "\n";
550  assert(lobby_info_.games().size() == gamelistbox_->get_item_count());
552 
554 }
555 
557 {
558  SCOPE_LB;
559  DBG_LB << "Playerlist update: " << lobby_info_.users().size() << "\n";
561 
562 #ifdef ENABLE_ROOM_MEMBER_TREE
563  bool lobby = false;
565  if(ri->name() == "lobby") {
566  lobby = true;
567  }
568  }
569 #endif
570 
571  assert(player_list_.active_game.tree);
572 #ifdef ENABLE_ROOM_MEMBER_TREE
573  assert(player_list_.active_room.tree);
574 #endif
575  assert(player_list_.other_games.tree);
576  assert(player_list_.other_rooms.tree);
577 
578  unsigned scrollbar_position = player_list_.tree->get_vertical_scrollbar_item_position();
579 
581 #ifdef ENABLE_ROOM_MEMBER_TREE
583 #endif
586 
587  for(auto& user : lobby_info_.users()) {
588  sub_player_list* target_list(nullptr);
589 
590  std::string name = user.name;
591 
592  std::stringstream icon_ss;
593  icon_ss << "lobby/status";
594  switch(user.state) {
595 #ifdef ENABLE_ROOM_MEMBER_TREE
597  icon_ss << "-lobby";
598  target_list = &player_list_.active_room;
599  if(lobby) {
600  target_list = &player_list_.other_rooms;
601  }
602  break;
603 #endif
605  icon_ss << "-lobby";
606  target_list = &player_list_.other_rooms;
607  break;
609  name = colorize(name, {0, 255, 255});
610  icon_ss << (user.observing ? "-obs" : "-playing");
611  target_list = &player_list_.active_game;
612  break;
613  case mp::user_info::GAME:
614  name = colorize(name, font::BAD_COLOR);
615  icon_ss << (user.observing ? "-obs" : "-playing");
616  target_list = &player_list_.other_games;
617  break;
618  default:
619  ERR_LB << "Bad user state in lobby: " << user.name << ": "
620  << user.state << "\n";
621  continue;
622  }
623 
624  switch(user.relation) {
625  case mp::user_info::ME:
626  icon_ss << "-s";
627  break;
629  icon_ss << "-n";
630  break;
632  icon_ss << "-f";
633  break;
635  icon_ss << "-i";
636  break;
637  default:
638  ERR_LB << "Bad user relation in lobby: " << user.relation
639  << "\n";
640  }
641 
642  // TODO: on the official server this results in every name being bold since we
643  // require a registered account. Leaving this commented out in case we ever
644  // walk that back and want to have such an indication again (it's useless for
645  // custom servers since registered logins aren't supported there).
646 #if 0
647  if(user.registered) {
648  name = "<b>" + name + "</b>";
649  }
650 #endif
651 
652  icon_ss << ".png";
653 
655  target_list = &player_list_.other_rooms;
656  }
657 
658  assert(target_list->tree);
659 
660  string_map tree_group_field;
661  std::map<std::string, string_map> tree_group_item;
662 
663  /*** Add tree item ***/
664  tree_group_field["label"] = icon_ss.str();
665  tree_group_item["icon"] = tree_group_field;
666 
667  tree_group_field["label"] = name;
668  tree_group_field["use_markup"] = "true";
669  tree_group_item["name"] = tree_group_field;
670 
671  tree_view_node& player = target_list->tree->add_child("player", tree_group_item);
672 
673  connect_signal_mouse_left_double_click(find_widget<toggle_panel>(&player, "tree_view_node_label", false),
674  std::bind(&mp_lobby::user_dialog_callback, this, &user));
675  }
676 
678 #ifdef ENABLE_ROOM_MEMBER_TREE
680 #endif
683 
684  // Don't attempt to restore the scroll position if the window hasn't been laid out yet
685  if(player_list_.tree->get_origin() != point{-1, -1}) {
687  }
688 
689  player_list_dirty_ = false;
690  last_lobby_update_ = SDL_GetTicks();
691 }
692 
694 {
695  const int idx = gamelistbox_->get_selected_row();
696  bool can_join = false, can_observe = false;
697 
698  if(idx >= 0) {
699  const mp::game_info& game = *lobby_info_.games()[idx];
700  can_observe = game.can_observe();
701  can_join = game.can_join();
702  selected_game_id_ = game.id;
703  } else {
704  selected_game_id_ = 0;
705  }
706 
707  find_widget<button>(get_window(), "observe_global", false).set_active(can_observe);
708  find_widget<button>(get_window(), "join_global", false).set_active(can_join);
709 
710  player_list_dirty_ = true;
711 }
712 
714 {
715  if(window.get_retval() == retval::CANCEL) {
716  return quit();
717  }
718 
719  return true;
720 }
721 
723 {
724  SCOPE_LB;
725 
726  gamelistbox_ = find_widget<listbox>(&window, "game_list", false, true);
727 
729  std::bind(&mp_lobby::gamelist_change_callback, this));
730 
731  player_list_.init(window);
732 
733  window.set_enter_disabled(true);
734 
735  // Exit hook to add a confirmation when quitting the Lobby.
736  window.set_exit_hook(std::bind(&mp_lobby::exit_hook, this, std::ref(window)));
737 
738  chatbox_ = find_widget<chatbox>(&window, "chat", false, true);
739 
740  window.keyboard_capture(chatbox_);
741 
746 
747  find_widget<button>(&window, "create", false).set_retval(CREATE);
748 
750  find_widget<button>(&window, "show_preferences", false),
751  std::bind(&mp_lobby::show_preferences_button_callback, this, std::ref(window)));
752 
754  find_widget<button>(&window, "join_global", false),
755  std::bind(&mp_lobby::enter_selected_game, this, DO_JOIN));
756 
757  find_widget<button>(&window, "join_global", false).set_active(false);
758 
760  find_widget<button>(&window, "observe_global", false),
761  std::bind(&mp_lobby::enter_selected_game, this, DO_OBSERVE));
762 
763  find_widget<button>(&window, "observe_global", false).set_active(false);
764 
765  menu_button& replay_options = find_widget<menu_button>(&window, "replay_options", false);
766 
768  replay_options.set_selected(1);
769  }
770 
772  replay_options.set_selected(2);
773  }
774 
775  connect_signal_notify_modified(replay_options,
776  std::bind(&mp_lobby::skip_replay_changed_callback, this, std::ref(window)));
777 
778  filter_friends_ = find_widget<toggle_button>(&window, "filter_with_friends", false, true);
779  filter_ignored_ = find_widget<toggle_button>(&window, "filter_without_ignored", false, true);
780  filter_slots_ = find_widget<toggle_button>(&window, "filter_vacant_slots", false, true);
781  filter_invert_ = find_widget<toggle_button>(&window, "filter_invert", false, true);
782  filter_text_ = find_widget<text_box>(&window, "filter_text", false, true);
783 
785  std::bind(&mp_lobby::game_filter_change_callback, this));
786 
787  connect_signal_notify_modified(*filter_ignored_,
788  std::bind(&mp_lobby::game_filter_change_callback, this));
789 
790  connect_signal_notify_modified(*filter_slots_,
791  std::bind(&mp_lobby::game_filter_change_callback, this));
792 
793  connect_signal_notify_modified(*filter_invert_,
794  std::bind(&mp_lobby::game_filter_change_callback, this));
795 
797  *filter_text_,
798  std::bind(&mp_lobby::game_filter_keypress_callback, this, _5));
799 
800  chatbox_->room_window_open(N_("lobby"), true, false);
803 
804  // Force first update to be directly.
805  update_gamelist();
807 
808  // TODO: currently getting a crash in the chatbox if we use this.
809  // -- vultraz, 2017-11-10
810  //mp_lobby::network_handler();
811 
814 
815  // Set up Lua plugin context
816  plugins_context_.reset(new plugins_context("Multiplayer Lobby"));
817 
818  plugins_context_->set_callback("join", [&, this](const config&) {
820  }, true);
821 
822  plugins_context_->set_callback("observe", [&, this](const config&) {
824  }, true);
825 
826  plugins_context_->set_callback("create", [&window](const config&) { window.set_retval(CREATE); }, true);
827  plugins_context_->set_callback("quit", [&window](const config&) { window.set_retval(retval::CANCEL); }, false);
828 
829  plugins_context_->set_callback("chat", [this](const config& cfg) { chatbox_->send_chat_message(cfg["message"], false); }, true);
830  plugins_context_->set_callback("select_game", [this](const config& cfg) {
831  selected_game_id_ = cfg.has_attribute("id") ? cfg["id"].to_int() : lobby_info_.games()[cfg["index"].to_int()]->id;
832  }, true);
833 
834  plugins_context_->set_accessor("game_list", [this](const config&) { return lobby_info_.gamelist(); });
835  plugins_context_->set_accessor("game_config", [this](const config&) { return game_config_; });
836 }
837 
838 void mp_lobby::post_show(window& /*window*/)
839 {
842  plugins_context_.reset();
843 }
844 
846 {
847  try {
848  config data;
849  if (network_connection_.receive_data(data)) {
850  process_network_data(data);
851  }
852  } catch (const wesnothd_error& e) {
853  LOG_LB << "caught wesnothd_error in network_handler: " << e.message << "\n";
854  throw;
855  }
856 
857  if ((SDL_GetTicks() - last_lobby_update_ < game_config::lobby_refresh)) {
858  return;
859  }
860 
862  //don't process a corrupted gamelist further to prevent crashes later.
863  return;
864  }
865 
869  } else {
870  update_gamelist();
871  gamelist_diff_update_ = true;
872  }
873  }
874 
878  }
879 }
880 
882 {
883  if(const config& error = data.child("error")) {
884  throw wesnothd_error(error["message"]);
885  } else if(data.child("gamelist")) {
886  process_gamelist(data);
887  } else if(const config& gamelist_diff = data.child("gamelist_diff")) {
888  process_gamelist_diff(gamelist_diff);
889  }
890 
892 }
893 
895 {
897  DBG_LB << "Received gamelist\n";
898  gamelist_dirty_ = true;
899  gamelist_diff_update_ = false;
900 }
901 
903 {
905  DBG_LB << "Received gamelist diff\n";
906  gamelist_dirty_ = true;
907  } else {
908  ERR_LB << "process_gamelist_diff failed!" << std::endl;
909  refresh_lobby();
910  }
911  const int joined = data.child_count("insert_child");
912  const int left = data.child_count("remove_child");
913  if(joined > 0 || left > 0) {
914  if(left > joined) {
916  } else {
918  }
919  }
920 }
921 
923 {
924  switch(mode) {
925  case DO_JOIN:
926  if(!game.can_join()) {
927  ERR_LB << "Attempted to join a game with no vacant slots" << std::endl;
928  return;
929  }
930 
931  break;
932  case DO_OBSERVE:
933  if(!game.can_observe()) {
934  ERR_LB << "Attempted to observe a game with observers disabled" << std::endl;
935  return;
936  }
937 
938  break;
939  case DO_EITHER:
940  if(game.can_join()) {
941  mode = DO_JOIN;
942  } else if(game.can_observe()) {
943  mode = DO_OBSERVE;
944  } else {
945  DBG_LB << "Cannot join or observe a game." << std::endl;
946  return;
947  }
948 
949  break;
950  }
951 
952  const bool try_join = mode == DO_JOIN;
953  const bool try_obsv = mode == DO_OBSERVE;
954 
955  window& window = *get_window();
956 
957  // Prompt user to download this game's required addons if its requirements have not been met
959  if(game.required_addons.empty()) {
960  gui2::show_error_message(_("Something is wrong with the addon version check database supporting the multiplayer lobby. Please report this at https://bugs.wesnoth.org."));
961  return;
962  }
963 
964  if(!handle_addon_requirements_gui(game.required_addons, game.addons_outcome)) {
965  return;
966  }
967 
968  // Addons have been downloaded, so the game_config and installed addons list need to be reloaded.
969  // The lobby is closed and reopened.
970  window.set_retval(RELOAD_CONFIG);
971  return;
972  }
973 
974  config response;
975 
976  config& join_data = response.add_child("join");
977  join_data["id"] = std::to_string(game.id);
978  join_data["observe"] = try_obsv;
979 
980  if(!join_data.empty() && game.password_required) {
981  std::string password;
982 
983  if(!gui2::dialogs::mp_join_game_password_prompt::execute(password)) {
984  return;
985  }
986 
987  join_data["password"] = password;
988  }
989 
990  network_connection_.send_data(response);
991  joined_game_id_ = game.id;
992 
993  // We're all good. Close lobby and proceed to game!
994  window.set_retval(try_join ? JOIN : OBSERVE);
995 }
996 
998 {
999  try {
1000  enter_game(*lobby_info_.games().at(index), mode);
1001  } catch(const std::out_of_range&) {
1002  // Game index was invalid!
1003  ERR_LB << "Attempted to join/observe a game with index out of range: " << index << ". "
1004  << "Games vector size is " << lobby_info_.games().size() << std::endl;
1005  }
1006 }
1007 
1008 void mp_lobby::enter_game_by_id(const int game_id, JOIN_MODE mode)
1009 {
1010  mp::game_info* game_ptr = lobby_info_.get_game_by_id(game_id);
1011 
1012  if(!game_ptr) {
1013  ERR_LB << "Attempted to join/observe a game with an invalid id: " << game_id << std::endl;
1014  return;
1015  }
1016 
1017  enter_game(*game_ptr, mode);
1018 }
1019 
1021 {
1023 }
1024 
1026 {
1027  network_connection_.send_data(config("refresh_lobby"));
1028 }
1029 
1031 {
1033 
1034  /**
1035  * The screen size might have changed force an update of the size.
1036  *
1037  * @todo This might no longer be needed when gui2 is done.
1038  */
1039  const SDL_Rect rect = window.video().screen_area();
1040 
1045 
1046  /**
1047  * The screen size might have changed force an update of the size.
1048  *
1049  * @todo This might no longer be needed when gui2 is done.
1050  */
1051  window.invalidate_layout();
1052 
1053  refresh_lobby();
1054 }
1055 
1057 {
1059 
1060  for(const auto& s : utils::split(filter_text_->get_value(), ' ')) {
1061  lobby_info_.add_game_filter([s](const mp::game_info& info)->bool {
1062  return info.match_string_filter(s);
1063  });
1064  }
1065 
1066  // TODO: make changing friend/ignore lists trigger a refresh
1067  if(filter_friends_->get_value()) {
1068  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1069  return info.has_friends == true;
1070  });
1071  }
1072 
1073  if(filter_ignored_->get_value()) {
1074  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1075  return info.has_ignored == false;
1076  });
1077  }
1078 
1079  if(filter_slots_->get_value()) {
1080  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1081  return info.vacant_slots > 0;
1082  });
1083  }
1084 
1086 }
1087 
1088 void mp_lobby::game_filter_keypress_callback(const SDL_Keycode key)
1089 {
1090  if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1093  }
1094 }
1095 
1097 {
1100 }
1101 
1103 {
1105 }
1106 
1108 {
1109  player_list_dirty_ = true;
1110  // get_window()->invalidate_layout();
1111 }
1112 
1114 {
1115  lobby_player_info dlg(*chatbox_, *info, lobby_info_);
1116 
1118 
1119  dlg.show();
1120 
1121  delay_playerlist_update_ = true;
1122 
1123  if(dlg.result_open_whisper()) {
1126  }
1127 
1128  selected_game_id_ = info->game_id;
1129 
1130  // do not update here as it can cause issues with removing the widget
1131  // from within it's event handler. Should get updated as soon as possible
1132  // update_gamelist();
1133  delay_playerlist_update_ = false;
1134  player_list_dirty_ = true;
1135  refresh_lobby();
1136 }
1137 
1139 {
1140  // TODO: this prefence should probably be controlled with an enum
1141  const int value = find_widget<menu_button>(&window, "replay_options", false).get_value();
1142  preferences::set_skip_mp_replay(value == 1);
1144 }
1145 
1146 } // namespace dialogs
1147 } // namespace gui2
Define the common log macros for the gui toolkit.
void game_filter_keypress_callback(const SDL_Keycode key)
Definition: lobby.cpp:1088
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:125
void active_window_changed()
Definition: chatbox.cpp:110
An error occurred during when trying to coommunicate with the wesnothd server.
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
Class for a toggle button.
std::string scenario
Definition: lobby_data.hpp:148
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
void set_selected(unsigned selected, bool fire_event=true)
std::string map_size_info
Definition: lobby_data.hpp:151
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:420
void set_map_data(const std::string &map_data)
Definition: minimap.hpp:60
ADDON_REQ addons_outcome
Definition: lobby_data.hpp:199
const config & gamelist() const
Returns the raw game list config data.
Definition: lobby_info.hpp:61
void set_lobby_info(mp::lobby_info &i)
Definition: chatbox.hpp:87
std::string status
Definition: lobby_data.hpp:161
#define ERR_LB
Definition: lobby.cpp:56
std::vector< int > gamelist_id_at_row_
Definition: lobby.hpp:206
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:997
Simple push button.
Definition: menu_button.hpp:41
std::vector< std::pair< std::string, bool > > mod_info
List of modification names and whether they&#39;re installed or not.
Definition: lobby_data.hpp:155
const color_t GRAY_COLOR
std::size_t lobby_update_timer_
Timer for updating the lobby.
Definition: lobby.hpp:204
text_box * filter_text_
Definition: lobby.hpp:187
sub_player_list active_room
Definition: lobby.hpp:55
const color_t GOOD_COLOR
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:203
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
logger & info()
Definition: log.cpp:90
#define a
This class represents the info a client has about a game on the server.
Definition: lobby_data.hpp:138
const color_t TITLE_COLOR
unsigned child_count(config_key_type key) const
Definition: config.cpp:390
#define DBG_LB
Definition: lobby.cpp:54
virtual void pre_show(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:722
std::string get_value() const
void update_user_statuses(int game_id, const room_info *room)
Definition: lobby_info.cpp:381
Base class for all widgets.
Definition: widget.hpp:47
This class represents the collective information the client has about the players and games on the se...
Definition: lobby_info.hpp:30
void skip_replay_changed_callback(window &window)
Definition: lobby.cpp:1138
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:69
void user_dialog_callback(mp::user_info *info)
Definition: lobby.cpp:1113
STL namespace.
void adjust_game_row_contents(const mp::game_info &game, grid *grid, bool add_callbacks=true)
Definition: lobby.cpp:437
window * get_window() const
Returns a pointer to the dialog&#39;s window.
#define LOG_LB
Definition: lobby.cpp:55
static bool logout_prompt()
Definition: lobby.cpp:113
unsigned gamemap_width
The size of the map area, if not available equal to the screen size.
Definition: settings.cpp:30
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:272
bool receive_data(config &result)
void process_network_data(const config &data)
Definition: lobby.cpp:881
void update_selected_game()
Definition: lobby.cpp:693
void enter_selected_game(JOIN_MODE mode)
Enter game by index, where index is the selected game listbox row.
Definition: lobby.cpp:1020
bool show(const unsigned auto_close_time=0)
Shows the window.
std::string name
Definition: lobby_data.hpp:147
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:162
void apply_game_filter()
Generates a new list of games that match the current filter functions and inversion setting...
Definition: lobby_info.cpp:356
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:250
static lg::log_domain log_lobby("lobby")
void update_gamelist_header()
Definition: lobby.cpp:398
std::size_t count_children() const
The number of children in this widget.
Generic file dialog.
Definition: field-fwd.hpp:22
void gamelist_change_callback()
Definition: lobby.cpp:1102
game_info * get_game_by_id(int id)
Returns info on a game with the given game ID.
Definition: lobby_info.cpp:275
void make_games_vector()
Generates a new vector of game pointers from the ID/game map.
Definition: lobby_info.cpp:341
virtual void set_label(const t_string &label)
sub_player_list other_rooms
Definition: lobby.hpp:56
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
Base container class.
Definition: grid.hpp:30
bool password_required
Definition: lobby_data.hpp:175
listbox * gamelistbox_
Definition: lobby.hpp:173
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:53
void set_active_window_changed_callback(const std::function< void(void)> &f)
Definition: chatbox.hpp:82
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:1008
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:248
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&#39;s ...
Definition: manager_ui.cpp:257
This file contains the settings handling of the widget library.
void init(window &w)
Definition: lobby.cpp:101
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:125
std::unique_ptr< plugins_context > plugins_context_
void set_visible(const visibility visible)
Definition: widget.cpp:473
unsigned lobby_network_timer
Definition: game_config.cpp:87
Implements a quit confirmation dialog.
void sync_games_display_status()
Definition: lobby_info.cpp:254
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:233
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:389
std::string vision
Definition: lobby_data.hpp:160
bool blindfold_replay()
Definition: game.cpp:615
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:243
void update_gamelist_filter()
Definition: lobby.cpp:544
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:95
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:118
std::string map_data
Definition: lobby_data.hpp:146
void set_game_filter_invert(bool value)
Sets whether the result of each game filter should be inverted.
Definition: lobby_info.hpp:81
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:131
Shows a yes and no button.
Definition: message.hpp:79
void player_filter_callback()
Definition: lobby.cpp:1107
void process_gamelist_diff(const config &data)
Definition: lobby.cpp:902
void update_gamelist_diff()
Definition: lobby.cpp:294
std::string gold
Definition: lobby_data.hpp:157
const color_t YELLOW_COLOR
void set_blindfold_replay(bool value)
Definition: game.cpp:620
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:243
std::map< std::string, string_map > make_game_row_data(const mp::game_info &game)
Definition: lobby.cpp:408
Various uncategorised dialogs.
CVideo & video()
Definition: window.hpp:353
static bool quit()
Shows the quit confirmation if needed.
int get_retval()
Definition: window.hpp:371
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:604
void process_network_data(const ::config &data)
Definition: chatbox.cpp:766
const boost::dynamic_bitset & games_visibility() const
Definition: lobby_info.hpp:130
void set_config(const ::config *terrain)
Definition: minimap.hpp:78
bool use_map_settings
Definition: lobby_data.hpp:172
std::string name
Definition: lobby_data.hpp:127
void clear()
Removes all child items from the widget.
void show_preferences_button_callback(window &window)
Definition: lobby.cpp:1030
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.
void network_handler()
Network polling callback.
Definition: lobby.cpp:845
void enter_game(const mp::game_info &game, JOIN_MODE mode)
Exits the lobby and enters the given game.
Definition: lobby.cpp:922
std::size_t i
Definition: function.cpp:933
const std::vector< game_info * > & games() const
Definition: lobby_info.hpp:125
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
Game configuration data as global variables.
Definition: build_info.cpp:49
static map_location::DIRECTION s
double g
Definition: astarsearch.cpp:64
bool gamelist_initialized() const
Definition: lobby_info.hpp:145
std::string password(const std::string &server, const std::string &login)
void game_filter_change_callback()
Definition: lobby.cpp:1096
Contains the gui2 timer routines.
toggle_button * filter_invert_
Definition: lobby.hpp:185
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
Holds a 2D point.
Definition: point.hpp:23
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:66
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:67
std::size_t add_timer(const uint32_t interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:126
bool can_observe() const
Definition: lobby_data.cpp:528
int w
void set_skip_mp_replay(bool value)
Definition: game.cpp:610
sub_player_list other_games
Definition: lobby.hpp:57
unsigned last_lobby_update_
Definition: lobby.hpp:197
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:364
#define N_(String)
Definition: gettext.hpp:99
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
Base class for all visible items.
const std::string unicode_bullet
Definition: constants.cpp:43
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
bool skip_mp_replay()
Definition: game.cpp:605
player_list player_list_
Definition: lobby.hpp:191
The basic minimap class.
Definition: minimap.hpp:39
void process_gamelist(const config &data)
Definition: lobby.cpp:894
void clear_game_filter()
Clears all game filter functions.
Definition: lobby_info.hpp:75
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:476
std::string era
Definition: lobby_data.hpp:152
bool grid()
Definition: general.cpp:505
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:237
This class represents the information a client has about another player.
Definition: lobby_data.hpp:104
tree_view_node * tree
Definition: lobby.hpp:45
virtual void post_build(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:167
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 &#39;snooping&#39; on the keypress.
Definition: dispatcher.cpp:228
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:54
lu_byte left
Definition: lparser.cpp:1026
std::size_t vacant_slots
Definition: lobby_data.hpp:163
std::map< std::string, chatroom_log > default_chat_log
Definition: chat_log.cpp:16
void set_wesnothd_connection(wesnothd_connection &c)
Definition: chatbox.hpp:92
unsigned lobby_refresh
Definition: game_config.cpp:88
this module manages the cache of images.
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:86
std::string message
Definition: exceptions.hpp:31
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
wesnothd_connection & network_connection_
Definition: lobby.hpp:201
game_display_status display_status
Definition: lobby_data.hpp:188
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:806
std::vector< required_addon > required_addons
Definition: lobby_data.hpp:198
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
mp::lobby_info & lobby_info_
Definition: lobby.hpp:175
Dialog was closed with the OK button.
Definition: retval.hpp:34
const std::vector< user_info > & users() const
Definition: lobby_info.hpp:135
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
bool can_join() const
Definition: lobby_data.cpp:523
mock_char c
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
Definition: video.cpp:286
tree_view_node & add_child(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Constructs a new child node.
Enables auto close.
Definition: message.hpp:69
virtual void post_show(window &window) override
Inherited from modal_dialog.
Definition: lobby.cpp:838
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:143
toggle_button * filter_ignored_
Definition: lobby.hpp:181
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:383
bool empty() const
Definition: config.cpp:884
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:297
bool exit_hook(window &window)
Definition: lobby.cpp:713
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:56
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
const color_t BAD_COLOR
toggle_button * filter_friends_
Definition: lobby.hpp:179
std::string xp
Definition: lobby_data.hpp:159
bool playerlist_group_players()
Definition: lobby.cpp:35
virtual unsigned get_value() const override
Inherited from selectable_item.
bool match_string_filter(const std::string &filter) const
Definition: lobby_data.cpp:550
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:167
const config & game_config_
Definition: lobby.hpp:171
toggle_button * filter_slots_
Definition: lobby.hpp:183
#define SCOPE_LB
Definition: lobby.cpp:57