The Battle for Wesnoth  1.17.0-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 
18 #include "gui/auxiliary/field.hpp"
20 #include "gui/dialogs/message.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 #include "gui/widgets/listbox.hpp"
32 #include "gui/widgets/minimap.hpp"
33 #include "gui/widgets/chatbox.hpp"
34 #include "gui/widgets/settings.hpp"
35 #include "gui/widgets/text_box.hpp"
40 
41 #include "addon/client.hpp"
42 #include "addon/manager_ui.hpp"
43 #include "chat_log.hpp"
44 #include "desktop/open.hpp"
45 #include "font/text_formatting.hpp"
46 #include "formatter.hpp"
47 #include "formula/string_utils.hpp"
48 #include "game_config_manager.hpp"
49 #include "preferences/game.hpp"
50 #include "gettext.hpp"
51 #include "help/help.hpp"
52 #include "preferences/lobby.hpp"
53 #include "playmp_controller.hpp"
54 #include "wesnothd_connection.hpp"
55 
56 #include <functional>
57 
58 static lg::log_domain log_lobby("lobby");
59 #define DBG_LB LOG_STREAM(debug, log_lobby)
60 #define LOG_LB LOG_STREAM(info, log_lobby)
61 #define ERR_LB LOG_STREAM(err, log_lobby)
62 #define SCOPE_LB log_scope2(log_lobby, __func__)
63 
64 namespace gui2::dialogs
65 {
66 
67 REGISTER_DIALOG(mp_lobby)
68 
69 void sub_player_list::init(window& w, const std::string& lbl, const bool unfolded)
70 {
71  tree_view& parent_tree = find_widget<tree_view>(&w, "player_tree", false);
72 
73  std::map<std::string, string_map> tree_group_item;
74  tree_group_item["tree_view_node_label"]["label"] = lbl;
75 
76  tree = &parent_tree.add_node("player_group", tree_group_item);
77 
78  if(unfolded) {
79  tree->unfold();
80  }
81 
82  tree_label = find_widget<label>(tree, "tree_view_node_label", false, true);
83  label_player_count = find_widget<label>(tree, "player_count", false, true);
84 
85  assert(tree_label);
86  assert(label_player_count);
87 }
88 
90 {
91  assert(tree);
92  assert(label_player_count);
93 
94  /**
95  * @todo Make sure setting visible resizes the widget.
96  *
97  * It doesn't work here since invalidate_layout is blocked, but the
98  * widget should also be able to handle it itself. Once done the
99  * setting of the label text can also be removed.
100  */
101  label_player_count->set_label((formatter() << "(" << tree->count_children() << ")").str());
102 }
103 
105 {
106  active_game.init(w, _("Selected Game"), true);
107  lobby_players.init(w, _("Lobby"), true);
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 
118 std::string mp_lobby::announcements_ = "";
119 std::string mp_lobby::server_information_ = "";
120 
122  : quit_confirmation(&mp_lobby::logout_prompt)
123  , game_config_(game_config_manager::get()->game_config())
124  , gamelistbox_(nullptr)
125  , lobby_info_(info)
126  , chatbox_(nullptr)
127  , filter_friends_(register_bool("filter_with_friends",
128  true,
131  std::bind(&mp_lobby::game_filter_change_callback, this)))
132  , filter_ignored_(register_bool("filter_with_ignored",
133  true,
136  std::bind(&mp_lobby::game_filter_change_callback, this)))
137  , filter_slots_(register_bool("filter_vacant_slots",
138  true,
141  std::bind(&mp_lobby::game_filter_change_callback, this)))
142  , filter_invert_(register_bool("filter_invert",
143  true,
146  std::bind(&mp_lobby::game_filter_change_callback, this)))
147  , filter_text_(nullptr)
148  , selected_game_id_()
149  , player_list_()
150  , player_list_dirty_(true)
151  , gamelist_dirty_(true)
152  , last_lobby_update_(0)
153  , gamelist_diff_update_(true)
154  , network_connection_(connection)
155  , lobby_update_timer_(0)
156  , gamelist_id_at_row_()
157  , delay_playerlist_update_(false)
158  , delay_gamelist_update_(false)
159  , joined_game_id_(joined_game)
160 {
161  // Need to set this in the constructor, pre_show() is too late
163  set_allow_plugin_skip(false);
165 }
166 
168 {
170  {
171  l.delay_gamelist_update_ = true;
172  }
174  {
175  l.delay_gamelist_update_ = false;
176  }
178 };
179 
181 {
182  if(lobby_update_timer_) {
184  }
185 }
186 
188 {
189  /*** Local hotkeys. ***/
191  std::bind(&mp_lobby::show_help_callback, this));
192 
195 }
196 
197 namespace
198 {
199 void modify_grid_with_data(grid* grid, const std::map<std::string, string_map>& map)
200 {
201  for(const auto& v : map) {
202  const std::string& key = v.first;
203  const string_map& strmap = v.second;
204 
205  widget* w = grid->find(key, false);
206  if(!w) {
207  continue;
208  }
209 
210  styled_widget* c = dynamic_cast<styled_widget*>(w);
211  if(!c) {
212  continue;
213  }
214 
215  for(const auto & vv : strmap) {
216  if(vv.first == "label") {
217  c->set_label(vv.second);
218  } else if(vv.first == "tooltip") {
219  c->set_tooltip(vv.second);
220  }
221  }
222  }
223 }
224 
225 std::string colorize(const std::string& str, const color_t& color)
226 {
227  return (formatter() << font::span_color(color) << str << "</span>").str();
228 }
229 
230 bool handle_addon_requirements_gui(const std::vector<mp::game_info::required_addon>& reqs, mp::game_info::addon_req addon_outcome)
231 {
232  if(addon_outcome == mp::game_info::addon_req::CANNOT_SATISFY) {
233  std::string e_title = _("Incompatible User-made Content");
234  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.");
235 
236  err_msg +="\n\n";
237  err_msg += _("Details:");
238  err_msg += "\n";
239 
240  for(const mp::game_info::required_addon & a : reqs) {
242  err_msg += font::unicode_bullet + " " + a.message + "\n";
243  }
244  }
245  gui2::show_message(e_title, err_msg, message::auto_close, true);
246 
247  return false;
248  } else if(addon_outcome == mp::game_info::addon_req::NEED_DOWNLOAD) {
249  std::string e_title = _("Missing User-made Content");
250  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?");
251 
252  err_msg +="\n\n";
253  err_msg += _("Details:");
254  err_msg += "\n";
255 
256  std::vector<std::string> needs_download;
257  for(const mp::game_info::required_addon & a : reqs) {
259  err_msg += font::unicode_bullet + " " + a.message + "\n";
260 
261  needs_download.push_back(a.addon_id);
262  }
263  }
264 
265  assert(needs_download.size() > 0);
266 
267  if(gui2::show_message(e_title, err_msg, message::yes_no_buttons, true) == gui2::retval::OK) {
268  // Begin download session
269  try {
270  return ad_hoc_addon_fetch_session(needs_download);
271  } catch (const addons_client::user_exit&) {
272  } catch (const addons_client::user_disconnect&) {
273  }
274  }
275  }
276 
277  return false;
278 }
279 
280 } // end anonymous namespace
281 
283 {
284  if(delay_gamelist_update_) return;
285 
286  SCOPE_LB;
287  gamelistbox_->clear();
288  gamelist_id_at_row_.clear();
290 
291  int select_row = -1;
292  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
293  const mp::game_info& game = *lobby_info_.games()[i];
294 
295  if(game.id == selected_game_id_) {
296  select_row = i;
297  }
298 
299  gamelist_id_at_row_.push_back(game.id);
300  LOG_LB << "Adding game to listbox (1)" << game.id << "\n";
302 
303  adjust_game_row_contents(game, grid);
304  }
305 
306  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
307  gamelistbox_->select_row(select_row);
308  }
309 
311  gamelist_dirty_ = false;
312  last_lobby_update_ = SDL_GetTicks();
317 }
318 
320 {
321  if(delay_gamelist_update_) return;
322 
323  SCOPE_LB;
325  int select_row = -1;
326  unsigned list_i = 0;
327  int list_rows_deleted = 0;
328 
329  std::vector<int> next_gamelist_id_at_row;
330  for(unsigned i = 0; i < lobby_info_.games().size(); ++i) {
331  const mp::game_info& game = *lobby_info_.games()[i];
332 
334  // call void do_notify(notify_mode mode, const std::string& sender, const std::string& message)
335  // sender will be the game_info.scenario (std::string) and message will be game_info.name (std::string)
336  if (lobby_info_.is_game_visible(game)) {
338  }
339 
340  LOG_LB << "Adding game to listbox " << game.id << "\n";
341 
342  if(list_i != gamelistbox_->get_item_count()) {
343  gamelistbox_->add_row(make_game_row_data(game), list_i);
344  DBG_LB << "Added a game listbox row not at the end" << list_i
345  << " " << gamelistbox_->get_item_count() << "\n";
346  list_rows_deleted--;
347  } else {
349  }
350 
352  adjust_game_row_contents(game, grid);
353 
354  list_i++;
355  next_gamelist_id_at_row.push_back(game.id);
356  } else {
357  if(list_i >= gamelistbox_->get_item_count()) {
358  ERR_LB << "Ran out of listbox items -- triggering a full refresh\n";
359  refresh_lobby();
360  return;
361  }
362 
363  if(list_i + list_rows_deleted >= gamelist_id_at_row_.size()) {
364  ERR_LB << "gamelist_id_at_row_ overflow! " << list_i << " + "
365  << list_rows_deleted
366  << " >= " << gamelist_id_at_row_.size()
367  << " -- triggering a full refresh\n";
368  refresh_lobby();
369  return;
370  }
371 
372  int listbox_game_id = gamelist_id_at_row_[list_i + list_rows_deleted];
373  if(game.id != listbox_game_id) {
374  ERR_LB << "Listbox game id does not match expected id "
375  << listbox_game_id << " " << game.id << " (row " << list_i << ")\n";
376  refresh_lobby();
377  return;
378  }
379 
381  LOG_LB << "Modifying game in listbox " << game.id << " (row " << list_i << ")\n";
382  grid* grid = gamelistbox_->get_row_grid(list_i);
383  modify_grid_with_data(grid, make_game_row_data(game));
384  adjust_game_row_contents(game, grid, false);
385  ++list_i;
386  next_gamelist_id_at_row.push_back(game.id);
388  LOG_LB << "Deleting game from listbox " << game.id << " (row "
389  << list_i << ")\n";
390  gamelistbox_->remove_row(list_i);
391  ++list_rows_deleted;
392  } else {
393  // clean
394  LOG_LB << "Clean game in listbox " << game.id << " (row " << list_i << ")\n";
395  next_gamelist_id_at_row.push_back(game.id);
396  ++list_i;
397  }
398  }
399  }
400 
401  for(unsigned i = 0; i < next_gamelist_id_at_row.size(); ++i) {
402  if(next_gamelist_id_at_row[i] == selected_game_id_) {
403  select_row = i;
404  }
405  }
406 
407  next_gamelist_id_at_row.swap(gamelist_id_at_row_);
408  if(select_row >= static_cast<int>(gamelistbox_->get_item_count())) {
409  ERR_LB << "Would select a row beyond the listbox" << select_row << " "
410  << gamelistbox_->get_item_count() << "\n";
411  select_row = gamelistbox_->get_item_count() - 1;
412  }
413 
414  if(select_row >= 0 && select_row != gamelistbox_->get_selected_row()) {
415  gamelistbox_->select_row(select_row);
416  }
417 
419  gamelist_dirty_ = false;
420  last_lobby_update_ = SDL_GetTicks();
425 }
426 
428 {
429  const std::string games_string = VGETTEXT("Games: showing $num_shown out of $num_total", {
430  {"num_shown", std::to_string(lobby_info_.games_visibility().count())},
431  {"num_total", std::to_string(lobby_info_.games().size())}
432  });
433 
434  find_widget<label>(gamelistbox_, "map", false).set_label(games_string);
435 }
436 
437 std::map<std::string, string_map> mp_lobby::make_game_row_data(const mp::game_info& game)
438 {
439  std::map<std::string, string_map> data;
441 
442  item["use_markup"] = "true";
443 
444  color_t color_string;
445  if(game.vacant_slots > 0) {
446  color_string = (game.reloaded || game.started) ? font::YELLOW_COLOR : font::GOOD_COLOR;
447  }
448 
449  const std::string scenario_text = VGETTEXT("$game_name (Era: $era_name)", {
450  {"game_name", game.scenario},
451  {"era_name", game.era}
452  });
453 
454  item["label"] = game.vacant_slots > 0 ? colorize(game.name, color_string) : game.name;
455  data.emplace("name", item);
456 
457  item["label"] = colorize(game.type_marker + "<i>" + scenario_text + "</i>", font::GRAY_COLOR);
458  data.emplace("scenario", item);
459 
460  item["label"] = colorize(game.status, color_string);
461  data.emplace("status", item);
462 
463  return data;
464 }
465 
467 {
468  find_widget<styled_widget>(grid, "name", false).set_use_markup(true);
469  find_widget<styled_widget>(grid, "status", false).set_use_markup(true);
470 
471  toggle_panel& row_panel = find_widget<toggle_panel>(grid, "panel", false);
472 
473  //
474  // Game info
475  //
476  std::ostringstream ss;
477 
478  const auto mark_missing = [&ss]() {
479  ss << ' ' << font::span_color(font::BAD_COLOR) << "(" << _("era_or_mod^not installed") << ")</span>";
480  };
481 
482  ss << "<big>" << colorize(_("Era"), font::TITLE_COLOR) << "</big>\n" << game.era;
483 
484  if(!game.have_era) {
485  // NOTE: not using colorize() here deliberately to avoid awkward string concatenation.
486  mark_missing();
487  }
488 
489  ss << "\n\n<big>" << colorize(_("Modifications"), font::TITLE_COLOR) << "</big>\n";
490 
491  auto mods = game.mod_info;
492 
493  if(mods.empty()) {
494  ss << _("active_modifications^None") << "\n";
495  } else {
496  for(const auto& mod : mods) {
497  ss << mod.first;
498 
499  if(!mod.second) {
500  mark_missing();
501  }
502 
503  ss << '\n';
504  }
505  }
506 
507  // TODO: move to some general area of the code.
508  const auto yes_or_no = [](bool val) { return val ? _("yes") : _("no"); };
509 
510  ss << "\n<big>" << colorize(_("Settings"), font::TITLE_COLOR) << "</big>\n";
511  ss << _("Experience modifier:") << " " << game.xp << "\n";
512  ss << _("Gold per village:") << " " << game.gold << "\n";
513  ss << _("Map size:") << " " << game.map_size_info << "\n";
514  ss << _("Reloaded:") << " " << yes_or_no(game.reloaded) << "\n";
515  ss << _("Shared vision:") << " " << game.vision << "\n";
516  ss << _("Shuffle sides:") << " " << yes_or_no(game.shuffle_sides) << "\n";
517  ss << _("Time limit:") << " " << game.time_limit << "\n";
518  ss << _("Use map settings:") << " " << yes_or_no(game.use_map_settings);
519 
520  image& info_icon = find_widget<image>(grid, "game_info", false);
521 
522  if(!game.have_era || !game.have_all_mods || !game.required_addons.empty()) {
523  info_icon.set_label("icons/icon-info-error.png");
524 
525  ss << "\n\n<span color='#f00' size='x-large'>! </span>";
526  ss << _("One or more add-ons need to be installed\nin order to join this game.");
527  } else {
528  info_icon.set_label("icons/icon-info.png");
529  }
530 
531  info_icon.set_tooltip(ss.str());
532 
533  //
534  // Password icon
535  //
536  image& password_icon = find_widget<image>(grid, "needs_password", false);
537 
538  if(game.password_required) {
540  } else {
542  }
543 
544  //
545  // Observer icon
546  //
547  image& observer_icon = find_widget<image>(grid, "observer_icon", false);
548 
549  if(game.observers) {
550  observer_icon.set_label("misc/eye.png");
551  observer_icon.set_tooltip( _("Observers allowed"));
552  } else {
553  observer_icon.set_label("misc/no_observer.png");
554  observer_icon.set_tooltip( _("Observers not allowed"));
555  }
556 
557  //
558  // Minimap
559  //
560  minimap& map = find_widget<minimap>(grid, "minimap", false);
561 
562  map.set_map_data(game.map_data);
563 
564  if(!add_callbacks) {
565  return;
566  }
567 
569  std::bind(&mp_lobby::enter_game_by_id, this, game.id, DO_EITHER));
570 }
571 
573 {
574  DBG_LB << "mp_lobby::update_gamelist_filter\n";
576  DBG_LB << "Games in lobby_info: " << lobby_info_.games().size()
577  << ", games in listbox: " << gamelistbox_->get_item_count() << "\n";
578  assert(lobby_info_.games().size() == gamelistbox_->get_item_count());
580 
582 }
583 
585 {
586  if(delay_playerlist_update_) return;
587 
588  SCOPE_LB;
589  DBG_LB << "Playerlist update: " << lobby_info_.users().size() << "\n";
591 
592  assert(player_list_.active_game.tree);
593  assert(player_list_.other_games.tree);
595 
596  unsigned scrollbar_position = player_list_.tree->get_vertical_scrollbar_item_position();
597 
601 
602  std::map<std::string, std::map<std::string, string_map>> lobby_player_items;
603  std::map<std::string, std::map<std::string, string_map>> active_game_items;
604  std::map<std::string, std::map<std::string, string_map>> other_game_items;
605  for(const auto& user : lobby_info_.users()) {
606  std::string name = user.name;
607 
608  std::stringstream icon_ss;
609 
610  icon_ss << "lobby/status";
611  switch(user.state) {
613  icon_ss << "-lobby";
614  break;
616  name = colorize(name, {0, 255, 255});
617  icon_ss << (user.observing ? "-obs" : "-playing");
618  break;
620  name = colorize(name, font::GRAY_COLOR);
621  icon_ss << (user.observing ? "-obs" : "-playing");
622  break;
623  default:
624  ERR_LB << "Bad user state in lobby: " << user.name << ": " << static_cast<int>(user.state) << "\n";
625  continue;
626  }
627 
628  switch(user.relation) {
630  icon_ss << "-s";
631  break;
633  icon_ss << "-n";
634  break;
636  icon_ss << "-f";
637  break;
639  icon_ss << "-i";
640  break;
641  default:
642  ERR_LB << "Bad user relation in lobby: " << static_cast<int>(user.relation) << "\n";
643  }
644 
645  icon_ss << ".png";
646 
647  string_map tree_group_field;
648  std::map<std::string, string_map> tree_group_item;
649 
650  /*** Add tree item ***/
651  tree_group_field["label"] = icon_ss.str();
652  tree_group_item["icon"] = tree_group_field;
653 
654  tree_group_field["label"] = name;
655  tree_group_field["use_markup"] = "true";
656  tree_group_item["name"] = tree_group_field;
657 
658  switch(user.state) {
660  lobby_player_items[user.name] = tree_group_item;
661  break;
663  active_game_items[user.name] = tree_group_item;
664  break;
666  other_game_items[user.name] = tree_group_item;
667  break;
668  default:
669  ERR_LB << "Bad user state in lobby: " << user.name << ": " << static_cast<int>(user.state) << "\n";
670  continue;
671  }
672  }
673 
674  for(const auto& player : player_list_.active_game.tree->replace_children("player", active_game_items)) {
675  connect_signal_mouse_left_double_click(find_widget<toggle_panel>(player.second.get(), "tree_view_node_label", false),
676  std::bind(&mp_lobby::user_dialog_callback, this, lobby_info_.get_user(player.first)));
677  }
678  for(const auto& player : player_list_.lobby_players.tree->replace_children("player", lobby_player_items)) {
679  connect_signal_mouse_left_double_click(find_widget<toggle_panel>(player.second.get(), "tree_view_node_label", false),
680  std::bind(&mp_lobby::user_dialog_callback, this, lobby_info_.get_user(player.first)));
681  }
682  for(const auto& player : player_list_.other_games.tree->replace_children("player", other_game_items)) {
683  connect_signal_mouse_left_double_click(find_widget<toggle_panel>(player.second.get(), "tree_view_node_label", false),
684  std::bind(&mp_lobby::user_dialog_callback, this, lobby_info_.get_user(player.first)));
685  }
686 
690 
691  // Don't attempt to restore the scroll position if the window hasn't been laid out yet
692  if(player_list_.tree->get_origin() != point{-1, -1}) {
694  }
695 
696  player_list_dirty_ = false;
697  last_lobby_update_ = SDL_GetTicks();
698 }
699 
701 {
702  const int idx = gamelistbox_->get_selected_row();
703  bool can_join = false, can_observe = false;
704 
705  if(idx >= 0) {
706  const mp::game_info& game = *lobby_info_.games()[idx];
707  can_observe = game.can_observe();
708  can_join = game.can_join();
709  selected_game_id_ = game.id;
710  } else {
711  selected_game_id_ = 0;
712  }
713 
714  find_widget<button>(get_window(), "observe_global", false).set_active(can_observe);
715  find_widget<button>(get_window(), "join_global", false).set_active(can_join);
716 
717  player_list_dirty_ = true;
718 }
719 
721 {
722  if(window.get_retval() == retval::CANCEL) {
723  return quit();
724  }
725 
726  return true;
727 }
728 
730 {
731  SCOPE_LB;
732 
733  gamelistbox_ = find_widget<listbox>(&window, "game_list", false, true);
734 
736  std::bind(&mp_lobby::gamelist_change_callback, this));
737 
738  player_list_.init(window);
739 
740  window.set_enter_disabled(true);
741 
742  // Exit hook to add a confirmation when quitting the Lobby.
743  window.set_exit_hook(std::bind(&mp_lobby::exit_hook, this, std::placeholders::_1));
744 
745  chatbox_ = find_widget<chatbox>(&window, "chat", false, true);
746 
747  window.keyboard_capture(chatbox_);
748 
752 
753  find_widget<button>(&window, "create", false).set_retval(CREATE);
754 
756  find_widget<button>(&window, "show_preferences", false),
758 
760  find_widget<button>(&window, "join_global", false),
761  std::bind(&mp_lobby::enter_selected_game, this, DO_JOIN));
762 
763  find_widget<button>(&window, "join_global", false).set_active(false);
764 
766  find_widget<button>(&window, "observe_global", false),
767  std::bind(&mp_lobby::enter_selected_game, this, DO_OBSERVE));
768 
770  find_widget<button>(&window, "server_info", false),
771  std::bind(&mp_lobby::show_server_info, this));
772 
773  find_widget<button>(&window, "observe_global", false).set_active(false);
774 
775  menu_button& replay_options = find_widget<menu_button>(&window, "replay_options", false);
776 
778  replay_options.set_selected(1);
779  }
780 
782  replay_options.set_selected(2);
783  }
784 
785  connect_signal_notify_modified(replay_options,
786  std::bind(&mp_lobby::skip_replay_changed_callback, this));
787 
788  filter_text_ = find_widget<text_box>(&window, "filter_text", false, true);
789 
791  *filter_text_,
792  std::bind(&mp_lobby::game_filter_keypress_callback, this, std::placeholders::_5));
793 
794  chatbox_->room_window_open(N_("lobby"), true, false);
797 
798  // Force first update to be directly.
799  update_gamelist();
801 
802  // TODO: currently getting a crash in the chatbox if we use this.
803  // -- vultraz, 2017-11-10
804  //mp_lobby::network_handler();
805 
808 
809  //
810  // Profile box
811  //
812  if(auto* profile_panel = find_widget<panel>(&window, "profile", false, false)) {
813  auto your_info = std::find_if(lobby_info_.users().begin(), lobby_info_.users().end(),
814  [](const auto& u) { return u.relation == mp::user_info::user_relation::ME; });
815 
816  if(your_info != lobby_info_.users().end()) {
817  find_widget<label>(profile_panel, "username", false).set_label(your_info->name);
818 
819  auto& profile_button = find_widget<button>(profile_panel, "view_profile", false);
820  if(your_info->forum_id != 0) {
821  connect_signal_mouse_left_click(profile_button,
822  std::bind(&desktop::open_object, mp::get_profile_link(your_info->forum_id)));
823  } else {
824  profile_button.set_active(false);
825  }
826 
827  // TODO: implement
828  find_widget<button>(profile_panel, "view_match_history", false).set_active(false);
829  }
830  }
831 
832  // Set up Lua plugin context
833  plugins_context_.reset(new plugins_context("Multiplayer Lobby"));
834 
835  plugins_context_->set_callback("join", [&, this](const config&) {
837  }, true);
838 
839  plugins_context_->set_callback("observe", [&, this](const config&) {
841  }, true);
842 
843  plugins_context_->set_callback("create", [&window](const config&) { window.set_retval(CREATE); }, true);
844  plugins_context_->set_callback("quit", [&window](const config&) { window.set_retval(retval::CANCEL); }, false);
845 
846  plugins_context_->set_callback("chat", [this](const config& cfg) { chatbox_->send_chat_message(cfg["message"], false); }, true);
847  plugins_context_->set_callback("select_game", [this](const config& cfg) {
848  selected_game_id_ = cfg.has_attribute("id") ? cfg["id"].to_int() : lobby_info_.games()[cfg["index"].to_int()]->id;
849  }, true);
850 
851  plugins_context_->set_accessor("game_list", [this](const config&) { return lobby_info_.gamelist(); });
852  //plugins_context_->set_accessor("game_config", [this](const config&) { return game_config_; });
853 }
854 
855 void mp_lobby::post_show(window& /*window*/)
856 {
859  plugins_context_.reset();
860 }
861 
863 {
864  try {
865  config data;
866  if (network_connection_.receive_data(data)) {
867  process_network_data(data);
868  }
869  } catch (const wesnothd_error& e) {
870  LOG_LB << "caught wesnothd_error in network_handler: " << e.message << "\n";
871  throw;
872  }
873 
874  if ((SDL_GetTicks() - last_lobby_update_ < game_config::lobby_refresh)) {
875  return;
876  }
877 
879  //don't process a corrupted gamelist further to prevent crashes later.
880  return;
881  }
882 
886  } else {
887  update_gamelist();
888  gamelist_diff_update_ = true;
889  }
890  }
891 
895  }
896 }
897 
899 {
900  if(const config& error = data.child("error")) {
901  throw wesnothd_error(error["message"]);
902  } else if(data.child("gamelist")) {
903  process_gamelist(data);
904  } else if(const config& gamelist_diff = data.child("gamelist_diff")) {
905  process_gamelist_diff(gamelist_diff);
906  } else if(const config& info = data.child("message")) {
907  if(info["type"] == "server_info") {
908  server_information_ = info["message"].str();
909  return;
910  } else if(info["type"] == "announcements") {
911  announcements_ = info["message"].str();
912  return;
913  }
914  }
915 
917 }
918 
920 {
922 
924  DBG_LB << "Received gamelist\n";
925  gamelist_dirty_ = true;
926  gamelist_diff_update_ = false;
927 }
928 
930 {
932 
934  DBG_LB << "Received gamelist diff\n";
935  gamelist_dirty_ = true;
936  } else {
937  ERR_LB << "process_gamelist_diff failed!" << std::endl;
938  refresh_lobby();
939  }
940  const int joined = data.child_count("insert_child");
941  const int left = data.child_count("remove_child");
942  if(joined > 0 || left > 0) {
943  if(left > joined) {
945  } else {
947  }
948  }
949 }
950 
952 {
953  switch(mode) {
954  case DO_JOIN:
955  if(!game.can_join()) {
956  ERR_LB << "Attempted to join a game with no vacant slots" << std::endl;
957  return;
958  }
959 
960  break;
961  case DO_OBSERVE:
962  if(!game.can_observe()) {
963  ERR_LB << "Attempted to observe a game with observers disabled" << std::endl;
964  return;
965  }
966 
967  break;
968  case DO_EITHER:
969  if(game.can_join()) {
970  mode = DO_JOIN;
971  } else if(game.can_observe()) {
972  mode = DO_OBSERVE;
973  } else {
974  DBG_LB << "Cannot join or observe a game." << std::endl;
975  return;
976  }
977 
978  break;
979  }
980 
981  const bool try_join = mode == DO_JOIN;
982  const bool try_obsv = mode == DO_OBSERVE;
983 
984  window& window = *get_window();
985 
986  // Prompt user to download this game's required addons if its requirements have not been met
988  if(game.required_addons.empty()) {
989  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."));
990  return;
991  }
992 
993  if(!handle_addon_requirements_gui(game.required_addons, game.addons_outcome)) {
994  return;
995  }
996 
997  // Addons have been downloaded, so the game_config and installed addons list need to be reloaded.
998  // The lobby is closed and reopened.
999  window.set_retval(RELOAD_CONFIG);
1000  return;
1001  }
1002 
1003  config response;
1004 
1005  config& join_data = response.add_child("join");
1006  join_data["id"] = std::to_string(game.id);
1007  join_data["observe"] = try_obsv;
1008 
1009  if(!join_data.empty() && game.password_required) {
1010  std::string password;
1011 
1012  if(!gui2::dialogs::mp_join_game_password_prompt::execute(password)) {
1013  return;
1014  }
1015 
1016  join_data["password"] = password;
1017  }
1018 
1019  network_connection_.send_data(response);
1020  joined_game_id_ = game.id;
1021 
1022  // We're all good. Close lobby and proceed to game!
1023  window.set_retval(try_join ? JOIN : OBSERVE);
1024 }
1025 
1027 {
1028  try {
1029  enter_game(*lobby_info_.games().at(index), mode);
1030  } catch(const std::out_of_range&) {
1031  // Game index was invalid!
1032  ERR_LB << "Attempted to join/observe a game with index out of range: " << index << ". "
1033  << "Games vector size is " << lobby_info_.games().size() << std::endl;
1034  }
1035 }
1036 
1037 void mp_lobby::enter_game_by_id(const int game_id, JOIN_MODE mode)
1038 {
1039  mp::game_info* game_ptr = lobby_info_.get_game_by_id(game_id);
1040 
1041  if(!game_ptr) {
1042  ERR_LB << "Attempted to join/observe a game with an invalid id: " << game_id << std::endl;
1043  return;
1044  }
1045 
1046  enter_game(*game_ptr, mode);
1047 }
1048 
1050 {
1052 }
1053 
1055 {
1056  network_connection_.send_data(config("refresh_lobby"));
1057 }
1058 
1060 {
1061  help::show_help();
1062 }
1063 
1065 {
1066  gui2::dialogs::preferences_dialog::display();
1067 
1068  /**
1069  * The screen size might have changed force an update of the size.
1070  *
1071  * @todo This might no longer be needed when gui2 is done.
1072  */
1073  const SDL_Rect rect = CVideo::get_singleton().screen_area();
1074 
1079 
1080  /**
1081  * The screen size might have changed force an update of the size.
1082  *
1083  * @todo This might no longer be needed when gui2 is done.
1084  */
1086 
1087  refresh_lobby();
1088 }
1089 
1091 {
1093 }
1094 
1096 {
1098 
1099  for(const auto& s : utils::split(filter_text_->get_value(), ' ')) {
1100  lobby_info_.add_game_filter([s](const mp::game_info& info)->bool {
1101  return info.match_string_filter(s);
1102  });
1103  }
1104 
1105  window& window = *get_window();
1106 
1107  // TODO: make changing friend/ignore lists trigger a refresh
1108  if(filter_friends_->get_widget_value(window)) {
1109  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1110  return info.has_friends == true;
1111  });
1112  }
1113 
1114  // Unlike the friends filter, this is an inclusion filter (do we want to also show
1115  // games with blocked players) rather than an exclusion filter (do we want to show
1116  // only games with friends).
1117  if(filter_ignored_->get_widget_value(window) == false) {
1118  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1119  return info.has_ignored == false;
1120  });
1121  }
1122 
1123  if(filter_slots_->get_widget_value(window)) {
1124  lobby_info_.add_game_filter([](const mp::game_info& info)->bool {
1125  return info.vacant_slots > 0;
1126  });
1127  }
1128 
1130 }
1131 
1132 void mp_lobby::game_filter_keypress_callback(const SDL_Keycode key)
1133 {
1134  if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1137  }
1138 }
1139 
1141 {
1144 }
1145 
1147 {
1149 }
1150 
1152 {
1153  player_list_dirty_ = true;
1154  // get_window()->invalidate_layout();
1155 }
1156 
1158 {
1159  delay_playerlist_update_ = true;
1161 
1162  lobby_player_info dlg(*chatbox_, *info, lobby_info_);
1163  dlg.show();
1164 
1165  if(dlg.result_open_whisper()) {
1168  }
1169 
1170  selected_game_id_ = info->game_id;
1171 
1172  // do not update here as it can cause issues with removing the widget
1173  // from within it's event handler. Should get updated as soon as possible
1174  // update_gamelist();
1175  delay_playerlist_update_ = false;
1176  player_list_dirty_ = true;
1177  refresh_lobby();
1178 }
1179 
1181 {
1182  // TODO: this prefence should probably be controlled with an enum
1183  const int value = find_widget<menu_button>(get_window(), "replay_options", false).get_value();
1184  preferences::set_skip_mp_replay(value == 1);
1186 }
1187 
1188 } // namespace dialogs
Define the common log macros for the gui toolkit.
void game_filter_keypress_callback(const SDL_Keycode key)
Definition: lobby.cpp:1132
void send_data(const configr_of &request)
Queues the given data to be sent to the server.
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 communicate with the wesnothd server.
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
Class for a toggle button.
static std::string announcements_
Definition: lobby.hpp:213
std::string scenario
Definition: lobby_data.hpp:150
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:154
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:414
void set_map_data(const std::string &map_data)
Definition: minimap.hpp:63
void skip_replay_changed_callback()
Definition: lobby.cpp:1180
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:143
const config & gamelist() const
Returns the raw game list config data.
Definition: lobby_info.hpp:61
field_bool * filter_invert_
Definition: lobby.hpp:181
std::string status
Definition: lobby_data.hpp:164
user_info * get_user(const std::string &name)
Returns info on the user with the given name, or nullptr if they don&#39;t eixst.
Definition: lobby_info.cpp:308
bool fi_vacant_slots()
Definition: lobby.cpp:45
#define ERR_LB
Definition: lobby.cpp:61
std::vector< int > gamelist_id_at_row_
Definition: lobby.hpp:202
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:1026
A menu_button is a styled_widget to choose an element from a list of elements.
Definition: menu_button.hpp:60
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:158
const color_t GRAY_COLOR
bool is_game_visible(const game_info &)
Returns whether the game would be visible after the game filters are applied.
Definition: lobby_info.cpp:346
std::size_t lobby_update_timer_
Timer for updating the lobby.
Definition: lobby.hpp:200
text_box * filter_text_
Definition: lobby.hpp:183
const color_t GOOD_COLOR
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:141
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
bool has_attribute(config_key_type key) const
Definition: config.cpp:207
logger & info()
Definition: log.cpp:88
#define a
This class represents the info a client has about a game on the server.
Definition: lobby_data.hpp:140
const color_t TITLE_COLOR
addon_req addons_outcome
Definition: lobby_data.hpp:203
void set_fi_vacant_slots(bool value)
Definition: lobby.cpp:50
unsigned child_count(config_key_type key) const
Definition: config.cpp:384
#define DBG_LB
Definition: lobby.cpp:59
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: lobby.cpp:729
std::string get_value() const
Base class for all widgets.
Definition: widget.hpp:48
static std::string server_information_
Definition: lobby.hpp:212
This class represents the collective information the client has about the players and games on the se...
Definition: lobby_info.hpp:30
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:1157
static CVideo & get_singleton()
Definition: video.hpp:48
STL namespace.
void adjust_game_row_contents(const mp::game_info &game, grid *grid, bool add_callbacks=true)
Definition: lobby.cpp:466
window * get_window() const
Returns a pointer to the dialog&#39;s window.
#define LOG_LB
Definition: lobby.cpp:60
static bool logout_prompt()
Definition: lobby.cpp:113
void set_fi_blocked_in_game(bool value)
Definition: lobby.cpp:70
void set_fi_friends_in_game(bool value)
Definition: lobby.cpp:60
unsigned gamemap_width
The size of the map area, if not available equal to the screen size.
Definition: settings.cpp:33
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
bool receive_data(config &result)
Receives the next pending data pack from the server, if available.
T get_widget_value(window &window)
Gets the value of the field.
Definition: field.hpp:395
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed...
void process_network_data(const config &data)
Definition: lobby.cpp:898
void update_selected_game()
Definition: lobby.cpp:700
static std::string _(const char *str)
Definition: gettext.hpp:92
void enter_selected_game(JOIN_MODE mode)
Enter game by index, where index is the selected game listbox row.
Definition: lobby.cpp:1049
bool show(const unsigned auto_close_time=0)
Shows the window.
field_bool * filter_ignored_
Definition: lobby.hpp:179
std::string name
Definition: lobby_data.hpp:149
void process_gamelist(const config &data)
Process a full game list.
Definition: lobby_info.cpp:109
std::string time_limit
Definition: lobby_data.hpp:165
void apply_game_filter()
Generates a new list of games that match the current filter functions and inversion setting...
Definition: lobby_info.cpp:364
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:251
static lg::log_domain log_lobby("lobby")
void update_gamelist_header()
Definition: lobby.cpp:427
bool fi_blocked_in_game()
Definition: lobby.cpp:65
std::size_t count_children() const
The number of children in this widget.
void gamelist_change_callback()
Definition: lobby.cpp:1146
game_info * get_game_by_id(int id)
Returns info on a game with the given game ID.
Definition: lobby_info.cpp:273
void make_games_vector()
Generates a new vector of game pointers from the ID/game map.
Definition: lobby_info.cpp:331
virtual void set_label(const t_string &label)
std::string get_profile_link(int user_id)
Gets the forum profile link for the given user.
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:178
Desktop environment interaction functions.
listbox * gamelistbox_
Definition: lobby.hpp:172
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:51
void update_user_statuses(int game_id)
Definition: lobby_info.cpp:375
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:1037
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:186
sub_player_list lobby_players
Definition: lobby.hpp:57
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:255
This file contains the settings handling of the widget library.
void init(window &w)
Definition: lobby.cpp:104
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:126
std::unique_ptr< plugins_context > plugins_context_
void set_visible(const visibility visible)
Definition: widget.cpp:475
unsigned lobby_network_timer
Definition: game_config.cpp:87
Implements a quit confirmation dialog.
void sync_games_display_status()
Definition: lobby_info.cpp:252
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:171
void show_preferences_button_callback()
Definition: lobby.cpp:1064
unsigned gamemap_height
Definition: settings.cpp:34
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:391
std::string vision
Definition: lobby_data.hpp:163
bool blindfold_replay()
Definition: game.cpp:604
A class that represents a TCP/IP connection to the wesnothd server.
void set_fi_invert(bool value)
Definition: lobby.cpp:40
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:245
void update_gamelist_filter()
Definition: lobby.cpp:572
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:95
disp_status display_status
Definition: lobby_data.hpp:192
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:655
std::string map_data
Definition: lobby_data.hpp:148
Modify, read and display user preferences.
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:132
Shows a yes and no button.
Definition: message.hpp:79
A tree view is a control that holds several items of the same or different types. ...
Definition: tree_view.hpp:59
void player_filter_callback()
Definition: lobby.cpp:1151
void process_gamelist_diff(const config &data)
Definition: lobby.cpp:929
void update_gamelist_diff()
Definition: lobby.cpp:319
std::string gold
Definition: lobby_data.hpp:160
const color_t YELLOW_COLOR
void set_blindfold_replay(bool value)
Definition: game.cpp:609
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:181
std::map< std::string, string_map > make_game_row_data(const mp::game_info &game)
Definition: lobby.cpp:437
static bool quit()
Shows the quit confirmation if needed.
int get_retval()
Definition: window.hpp:364
void process_network_data(const ::config &data)
Definition: chatbox.cpp:654
const boost::dynamic_bitset & games_visibility() const
Definition: lobby_info.hpp:108
bool use_map_settings
Definition: lobby_data.hpp:175
std::string name
Definition: lobby_data.hpp:127
void clear()
Removes all child items from the widget.
bool open_object([[maybe_unused]] const std::string &path_or_url)
Definition: open.cpp:46
void network_handler()
Network polling callback.
Definition: lobby.cpp:862
void enter_game(const mp::game_info &game, JOIN_MODE mode)
Exits the lobby and enters the given game.
Definition: lobby.cpp:951
std::size_t i
Definition: function.cpp:940
static void display(const std::string &info, const std::string &announcements)
The display function.
const std::vector< game_info * > & games() const
Definition: lobby_info.hpp:103
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:58
static map_location::DIRECTION s
double g
Definition: astarsearch.cpp:64
bool gamelist_initialized() const
Definition: lobby_info.hpp:123
std::string password(const std::string &server, const std::string &login)
void game_filter_change_callback()
Definition: lobby.cpp:1140
std::string type_marker
Definition: lobby_data.hpp:151
Contains the gui2 timer routines.
CURSOR_TYPE get()
Definition: cursor.cpp:215
std::map< std::string, t_string > string_map
Definition: widget.hpp:25
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:67
unsigned screen_width
The screen resolution and pixel pitch should be available for all widgets since their drawing method ...
Definition: settings.cpp:28
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:539
int w
void set_skip_mp_replay(bool value)
Definition: game.cpp:599
sub_player_list other_games
Definition: lobby.hpp:58
unsigned last_lobby_update_
Definition: lobby.hpp:193
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:357
#define N_(String)
Definition: gettext.hpp:100
mp_lobby(mp::lobby_info &info, wesnothd_connection &connection, int &joined_game)
Definition: lobby.cpp:121
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:46
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
bool skip_mp_replay()
Definition: game.cpp:594
player_list player_list_
Definition: lobby.hpp:187
The basic minimap class.
Definition: minimap.hpp:42
void process_gamelist(const config &data)
Definition: lobby.cpp:919
bool fi_invert()
Definition: lobby.cpp:35
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:129
config & add_child(config_key_type key)
Definition: config.cpp:500
std::string era
Definition: lobby_data.hpp:155
bool grid()
Definition: general.cpp:524
bool fi_friends_in_game()
Definition: lobby.cpp:55
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:238
This class represents the information a client has about another player.
Definition: lobby_data.hpp:104
tree_view_node * tree
Definition: lobby.hpp:47
virtual void post_build(window &window) override
Actions to be taken directly after the window is build.
Definition: lobby.cpp:187
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:166
void set_allow_plugin_skip(const bool allow_plugin_skip)
double t
Definition: astarsearch.cpp:64
unsigned screen_height
Definition: settings.cpp:29
The user sets the widget hidden, that means:
std::vector< std::string > split(const config_attribute_value &val)
sub_player_list active_game
Definition: lobby.hpp:56
lu_byte left
Definition: lparser.cpp:1226
field_bool * filter_slots_
Definition: lobby.hpp:180
std::size_t vacant_slots
Definition: lobby_data.hpp:166
std::map< std::string, chatroom_log > default_chat_log
Definition: chat_log.cpp:16
void set_wesnothd_connection(wesnothd_connection &c)
Definition: chatbox.hpp:87
unsigned lobby_refresh
Definition: game_config.cpp:88
std::map< std::string, std::shared_ptr< gui2::tree_view_node > > replace_children(const std::string &id, const std::map< std::string, std::map< std::string, string_map >> &data)
Replaces all children of this tree with new children.
Functions to load and save images from/to disk.
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:87
std::string message
Definition: exceptions.hpp:29
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
wesnothd_connection & network_connection_
Definition: lobby.hpp:197
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:798
std::vector< required_addon > required_addons
Definition: lobby_data.hpp:202
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:205
field_bool * filter_friends_
Definition: lobby.hpp:178
#define e
mp::lobby_info & lobby_info_
Definition: lobby.hpp:174
Dialog was closed with the OK button.
Definition: retval.hpp:34
const std::vector< user_info > & users() const
Definition: lobby_info.hpp:113
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
bool can_join() const
Definition: lobby_data.cpp:534
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:270
Enables auto close.
Definition: message.hpp:69
void set_retval(int retval)
Convenience wrapper to set the window&#39;s exit code.
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
Definition: lobby.cpp:855
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:144
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:385
bool empty() const
Definition: config.cpp:916
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:299
Networked add-ons (campaignd) client interface.
bool exit_hook(window &window)
Definition: lobby.cpp:720
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:409
const color_t BAD_COLOR
std::string xp
Definition: lobby_data.hpp:162
bool match_string_filter(const std::string &filter) const
Definition: lobby_data.cpp:561
void set_always_save_fields(const bool always_save_fields)
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:167
#define SCOPE_LB
Definition: lobby.cpp:62